Merge "Let getOriginalMimeType() take a fd passed from drm java applications" into jb-mr1-dev
diff --git a/api/17.txt b/api/17.txt
index 984b844..d002449 100644
--- a/api/17.txt
+++ b/api/17.txt
@@ -9802,7 +9802,7 @@
     method public float getZ();
   }
 
-  public class Sensor {
+  public final class Sensor {
     method public float getMaximumRange();
     method public int getMinDelay();
     method public java.lang.String getName();
@@ -24500,7 +24500,6 @@
     field public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0
     field public static final int SYSTEM_UI_LAYOUT_FLAGS = 1536; // 0x600
     field public static final int TEXT_ALIGNMENT_INHERIT = 0; // 0x0
-    field public static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = 131072; // 0x20000
     field public static final android.util.Property TRANSLATION_X;
     field public static final android.util.Property TRANSLATION_Y;
     field protected static final java.lang.String VIEW_LOG_TAG = "View";
diff --git a/api/current.txt b/api/current.txt
index 9c6c437..8a7fb79 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -68,6 +68,7 @@
     field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
     field public static final java.lang.String MANAGE_ACCOUNTS = "android.permission.MANAGE_ACCOUNTS";
     field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
+    field public static final java.lang.String MANAGE_USERS = "android.permission.MANAGE_USERS";
     field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
     field public static final java.lang.String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS";
     field public static final java.lang.String MODIFY_PHONE_STATE = "android.permission.MODIFY_PHONE_STATE";
@@ -3870,6 +3871,8 @@
     method public android.content.IntentSender getIntentSender();
     method public static android.app.PendingIntent getService(android.content.Context, int, android.content.Intent, int);
     method public java.lang.String getTargetPackage();
+    method public int getTargetUid();
+    method public android.os.UserHandle getTargetUserHandle();
     method public static android.app.PendingIntent readPendingIntentOrNullFromParcel(android.os.Parcel);
     method public void send() throws android.app.PendingIntent.CanceledException;
     method public void send(int) throws android.app.PendingIntent.CanceledException;
@@ -5262,6 +5265,7 @@
     method public abstract int checkUriPermission(android.net.Uri, int, int, int);
     method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public abstract deprecated void clearWallpaper() throws java.io.IOException;
+    method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
     method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] databaseList();
     method public abstract boolean deleteDatabase(java.lang.String);
@@ -5320,10 +5324,10 @@
     method public abstract void revokeUriPermission(android.net.Uri, int);
     method public abstract void sendBroadcast(android.content.Intent);
     method public abstract void sendBroadcast(android.content.Intent, java.lang.String);
-    method public abstract void sendBroadcastToUser(android.content.Intent, int);
+    method public abstract void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String);
     method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public abstract void sendOrderedBroadcastToUser(android.content.Intent, int, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public abstract void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public abstract void sendStickyBroadcast(android.content.Intent);
     method public abstract void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public abstract void setTheme(int);
@@ -5406,6 +5410,7 @@
     method public int checkUriPermission(android.net.Uri, int, int, int);
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public void clearWallpaper() throws java.io.IOException;
+    method public android.content.Context createConfigurationContext(android.content.res.Configuration);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
     method public boolean deleteDatabase(java.lang.String);
@@ -5456,10 +5461,10 @@
     method public void revokeUriPermission(android.net.Uri, int);
     method public void sendBroadcast(android.content.Intent);
     method public void sendBroadcast(android.content.Intent, java.lang.String);
-    method public void sendBroadcastToUser(android.content.Intent, int);
+    method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     method public void sendOrderedBroadcast(android.content.Intent, java.lang.String);
     method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void sendOrderedBroadcastToUser(android.content.Intent, int, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void sendStickyBroadcast(android.content.Intent);
     method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void setTheme(int);
@@ -5833,7 +5838,7 @@
     field public static final java.lang.String EXTRA_KEY_EVENT = "android.intent.extra.KEY_EVENT";
     field public static final java.lang.String EXTRA_LOCAL_ONLY = "android.intent.extra.LOCAL_ONLY";
     field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
-    field public static final java.lang.String EXTRA_ORIGINATING_URL = "android.intent.extra.ORIGINATING_URL";
+    field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
     field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
     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";
@@ -5984,6 +5989,8 @@
   public class IntentSender implements android.os.Parcelable {
     method public int describeContents();
     method public java.lang.String getTargetPackage();
+    method public int getTargetUid();
+    method public android.os.UserHandle getTargetUserHandle();
     method public static android.content.IntentSender readIntentSenderOrNullFromParcel(android.os.Parcel);
     method public void sendIntent(android.content.Context, int, android.content.Intent, android.content.IntentSender.OnFinished, android.os.Handler) throws android.content.IntentSender.SendIntentException;
     method public void sendIntent(android.content.Context, int, android.content.Intent, android.content.IntentSender.OnFinished, android.os.Handler, java.lang.String) throws android.content.IntentSender.SendIntentException;
@@ -9848,7 +9855,7 @@
     method public float getZ();
   }
 
-  public class Sensor {
+  public final class Sensor {
     method public float getMaximumRange();
     method public int getMinDelay();
     method public java.lang.String getName();
@@ -9974,6 +9981,15 @@
 package android.hardware.display {
 
   public final class DisplayManager {
+    method public android.view.Display getDisplay(int, android.content.Context);
+    method public void registerDisplayListener(android.hardware.display.DisplayManager.DisplayListener, android.os.Handler);
+    method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
+  }
+
+  public static abstract interface DisplayManager.DisplayListener {
+    method public abstract void onDisplayAdded(int);
+    method public abstract void onDisplayChanged(int);
+    method public abstract void onDisplayRemoved(int);
   }
 
 }
@@ -10550,7 +10566,7 @@
     method public android.os.Bundle getExtras();
     method public double getLatitude();
     method public double getLongitude();
-    method public java.lang.String getProvider();
+    method public deprecated java.lang.String getProvider();
     method public float getSpeed();
     method public long getTime();
     method public boolean hasAccuracy();
@@ -10588,6 +10604,7 @@
   }
 
   public class LocationManager {
+    method public void addGeofence(android.location.LocationRequest, android.location.Geofence, android.app.PendingIntent);
     method public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
     method public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
     method public deprecated void addProximityAlert(double, double, float, long, android.app.PendingIntent);
@@ -10599,7 +10616,7 @@
     method public deprecated java.lang.String getBestProvider(android.location.Criteria, boolean);
     method public android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
     method public deprecated android.location.Location getLastKnownLocation(java.lang.String);
-    method public android.location.Location getLastLocation(android.location.LocationRequest);
+    method public android.location.Location getLastLocation();
     method public deprecated android.location.LocationProvider getProvider(java.lang.String);
     method public deprecated java.util.List<java.lang.String> getProviders(boolean);
     method public deprecated java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
@@ -10612,7 +10629,6 @@
     method public deprecated void removeTestProvider(java.lang.String);
     method public void removeUpdates(android.location.LocationListener);
     method public void removeUpdates(android.app.PendingIntent);
-    method public void requestGeofence(android.location.LocationRequest, android.location.Geofence, android.app.PendingIntent);
     method public deprecated void requestLocationUpdates(java.lang.String, long, float, android.location.LocationListener);
     method public deprecated void requestLocationUpdates(java.lang.String, long, float, android.location.LocationListener, android.os.Looper);
     method public deprecated void requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper);
@@ -13210,6 +13226,7 @@
     field public java.lang.String capabilities;
     field public int frequency;
     field public int level;
+    field public long timestamp;
   }
 
   public final class SupplicantState extends java.lang.Enum implements android.os.Parcelable {
@@ -15508,6 +15525,7 @@
     field public static final int BATTERY_HEALTH_UNSPECIFIED_FAILURE = 6; // 0x6
     field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
     field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
+    field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
     field public static final int BATTERY_STATUS_CHARGING = 2; // 0x2
     field public static final int BATTERY_STATUS_DISCHARGING = 3; // 0x3
     field public static final int BATTERY_STATUS_FULL = 5; // 0x5
@@ -16267,6 +16285,7 @@
     method public android.os.PowerManager.WakeLock newWakeLock(int, java.lang.String);
     method public void reboot(java.lang.String);
     method public void userActivity(long, boolean);
+    method public void wakeUp(long);
     field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
     field public static final deprecated int FULL_WAKE_LOCK = 26; // 0x1a
     field public static final int ON_AFTER_RELEASE = 536870912; // 0x20000000
@@ -16294,7 +16313,7 @@
     method public static final int myPid();
     method public static final int myTid();
     method public static final int myUid();
-    method public static final int myUserHandle();
+    method public static final android.os.UserHandle myUserHandle();
     method public static final void sendSignal(int, int);
     method public static final void setThreadPriority(int, int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
     method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
@@ -16449,6 +16468,15 @@
     ctor public TransactionTooLargeException();
   }
 
+  public final class UserHandle implements android.os.Parcelable {
+    ctor public UserHandle(android.os.Parcel);
+    method public int describeContents();
+    method public static android.os.UserHandle readFromParcel(android.os.Parcel);
+    method public void writeToParcel(android.os.Parcel, int);
+    method public static void writeToParcel(android.os.UserHandle, android.os.Parcel);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public class UserManager {
     method public java.lang.String getUserName();
     method public boolean supportsMultipleUsers();
@@ -17233,9 +17261,11 @@
     field public static final java.lang.String DURATION = "duration";
     field public static final int INCOMING_TYPE = 1; // 0x1
     field public static final java.lang.String IS_READ = "is_read";
+    field public static final java.lang.String LIMIT_PARAM_KEY = "limit";
     field public static final int MISSED_TYPE = 3; // 0x3
     field public static final java.lang.String NEW = "new";
     field public static final java.lang.String NUMBER = "number";
+    field public static final java.lang.String OFFSET_PARAM_KEY = "offset";
     field public static final int OUTGOING_TYPE = 2; // 0x2
     field public static final java.lang.String TYPE = "type";
   }
@@ -18755,7 +18785,7 @@
     field public static final android.net.Uri DEFAULT_NOTIFICATION_URI;
     field public static final android.net.Uri DEFAULT_RINGTONE_URI;
     field public static final deprecated java.lang.String DEVICE_PROVISIONED = "device_provisioned";
-    field public static final java.lang.String DIM_SCREEN = "dim_screen";
+    field public static final deprecated java.lang.String DIM_SCREEN = "dim_screen";
     field public static final java.lang.String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
     field public static final java.lang.String END_BUTTON_BEHAVIOR = "end_button_behavior";
     field public static final java.lang.String FONT_SCALE = "font_scale";
@@ -19958,6 +19988,10 @@
 
 package android.security {
 
+  public class AndroidKeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
+    ctor public AndroidKeyPairGeneratorSpec(android.content.Context, java.lang.String, javax.security.auth.x500.X500Principal, java.math.BigInteger, java.util.Date, java.util.Date);
+  }
+
   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);
@@ -21146,6 +21180,7 @@
     method public int checkUriPermission(android.net.Uri, int, int, int);
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public void clearWallpaper();
+    method public android.content.Context createConfigurationContext(android.content.res.Configuration);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
     method public boolean deleteDatabase(java.lang.String);
@@ -21195,10 +21230,10 @@
     method public void revokeUriPermission(android.net.Uri, int);
     method public void sendBroadcast(android.content.Intent);
     method public void sendBroadcast(android.content.Intent, java.lang.String);
-    method public void sendBroadcastToUser(android.content.Intent, int);
+    method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     method public void sendOrderedBroadcast(android.content.Intent, java.lang.String);
     method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void sendOrderedBroadcastToUser(android.content.Intent, int, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void sendStickyBroadcast(android.content.Intent);
     method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void setTheme(int);
@@ -22474,6 +22509,17 @@
     method public abstract void chooseHeight(java.lang.CharSequence, int, int, int, int, android.graphics.Paint.FontMetricsInt, android.text.TextPaint);
   }
 
+  public class LocaleSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
+    ctor public LocaleSpan(java.util.Locale);
+    ctor public LocaleSpan(android.os.Parcel);
+    method public int describeContents();
+    method public java.util.Locale getLocale();
+    method public int getSpanTypeId();
+    method public void updateDrawState(android.text.TextPaint);
+    method public void updateMeasureState(android.text.TextPaint);
+    method public void writeToParcel(android.os.Parcel, int);
+  }
+
   public class MaskFilterSpan extends android.text.style.CharacterStyle implements android.text.style.UpdateAppearance {
     ctor public MaskFilterSpan(android.graphics.MaskFilter);
     method public android.graphics.MaskFilter getMaskFilter();
@@ -22866,6 +22912,8 @@
     method public static float cos(float);
     method public static float exp(float);
     method public static float floor(float);
+    method public static float hypot(float, float);
+    method public static float pow(float, float);
     method public static float sin(float);
     method public static float sqrt(float);
   }
@@ -23350,6 +23398,7 @@
   public class ContextThemeWrapper extends android.content.ContextWrapper {
     ctor public ContextThemeWrapper();
     ctor public ContextThemeWrapper(android.content.Context, int);
+    method public void applyOverrideConfiguration(android.content.res.Configuration);
     method protected void onApplyThemeResource(android.content.res.Resources.Theme, int, boolean);
   }
 
@@ -24557,6 +24606,7 @@
     method public final android.content.Context getContext();
     method protected android.view.ContextMenu.ContextMenuInfo getContextMenuInfo();
     method public static int getDefaultSize(int, int);
+    method public android.view.Display getDisplay();
     method public final int[] getDrawableState();
     method public android.graphics.Bitmap getDrawingCache();
     method public android.graphics.Bitmap getDrawingCache(boolean);
@@ -25007,16 +25057,15 @@
     field public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0
     field public static final int SYSTEM_UI_LAYOUT_FLAGS = 1536; // 0x600
     field public static final int TEXT_ALIGNMENT_CENTER = 4; // 0x4
-    field protected static int TEXT_ALIGNMENT_DEFAULT;
+    field public static int TEXT_ALIGNMENT_DEFAULT;
     field public static final int TEXT_ALIGNMENT_GRAVITY = 1; // 0x1
     field public static final int TEXT_ALIGNMENT_INHERIT = 0; // 0x0
-    field public static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = 131072; // 0x20000
     field public static final int TEXT_ALIGNMENT_TEXT_END = 3; // 0x3
     field public static final int TEXT_ALIGNMENT_TEXT_START = 2; // 0x2
     field public static final int TEXT_ALIGNMENT_VIEW_END = 6; // 0x6
     field public static final int TEXT_ALIGNMENT_VIEW_START = 5; // 0x5
     field public static final int TEXT_DIRECTION_ANY_RTL = 2; // 0x2
-    field protected static int TEXT_DIRECTION_DEFAULT;
+    field public static int TEXT_DIRECTION_DEFAULT;
     field public static final int TEXT_DIRECTION_FIRST_STRONG = 1; // 0x1
     field public static final int TEXT_DIRECTION_INHERIT = 0; // 0x0
     field public static final int TEXT_DIRECTION_LOCALE = 5; // 0x5
@@ -26905,6 +26954,7 @@
     method public synchronized boolean getUseWideViewPort();
     method public deprecated synchronized int getUserAgent();
     method public synchronized java.lang.String getUserAgentString();
+    method public static java.lang.String getDefaultUserAgent(android.content.Context);
     method public void setAllowContentAccess(boolean);
     method public void setAllowFileAccess(boolean);
     method public abstract void setAllowFileAccessFromFileURLs(boolean);
@@ -29272,6 +29322,7 @@
     method public static int getTextColor(android.content.Context, android.content.res.TypedArray, int);
     method public final android.content.res.ColorStateList getTextColors();
     method public static android.content.res.ColorStateList getTextColors(android.content.Context, android.content.res.TypedArray);
+    method public java.util.Locale getTextLocale();
     method public float getTextScaleX();
     method public float getTextSize();
     method public int getTotalPaddingBottom();
@@ -29374,6 +29425,7 @@
     method public void setTextIsSelectable(boolean);
     method public final void setTextKeepState(java.lang.CharSequence);
     method public final void setTextKeepState(java.lang.CharSequence, android.widget.TextView.BufferType);
+    method public void setTextLocale(java.util.Locale);
     method public void setTextScaleX(float);
     method public void setTextSize(float);
     method public void setTextSize(int, float);
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index d94daf7..c16e6fb 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -213,18 +213,30 @@
 
 int delete_persona(uid_t persona)
 {
-    char pkgdir[PKG_PATH_MAX];
-
-    if (create_persona_path(pkgdir, persona))
+    char data_path[PKG_PATH_MAX];
+    if (create_persona_path(data_path, persona)) {
         return -1;
+    }
+    if (delete_dir_contents(data_path, 1, NULL)) {
+        return -1;
+    }
 
-    return delete_dir_contents(pkgdir, 1, NULL);
+    char media_path[PATH_MAX];
+    if (create_persona_media_path(media_path, (userid_t) persona) == -1) {
+        return -1;
+    }
+    if (delete_dir_contents(media_path, 1, NULL) == -1) {
+        return -1;
+    }
+
+    return 0;
 }
 
 int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
 {
     char src_data_dir[PKG_PATH_MAX];
     char pkg_path[PKG_PATH_MAX];
+    char media_path[PATH_MAX];
     DIR *d;
     struct dirent *de;
     struct stat s;
@@ -233,6 +245,9 @@
     if (create_persona_path(src_data_dir, src_persona)) {
         return -1;
     }
+    if (create_persona_media_path(media_path, (userid_t) target_persona) == -1) {
+        return -1;
+    }
 
     d = opendir(src_data_dir);
     if (d != NULL) {
@@ -260,6 +275,11 @@
         }
         closedir(d);
     }
+
+    // ensure /data/media/<user_id> exists
+    if (ensure_dir(media_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
+        return -1;
+    }
     return 0;
 }
 
@@ -412,7 +432,7 @@
     return 0;
 }
 
-int get_size(const char *pkgname, const char *apkpath,
+int get_size(const char *pkgname, int persona, const char *apkpath,
              const char *fwdlock_apkpath, const char *asecpath,
              int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
              int64_t* _asecsize)
@@ -459,7 +479,7 @@
         }
     }
 
-    if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, 0)) {
+    if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, persona)) {
         goto done;
     }
 
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 89c059e..7108d68 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -85,8 +85,9 @@
     int64_t asecsize = 0;
     int res = 0;
 
-        /* pkgdir, apkpath */
-    res = get_size(arg[0], arg[1], arg[2], arg[3], &codesize, &datasize, &cachesize, &asecsize);
+        /* pkgdir, persona, apkpath */
+    res = get_size(arg[0], atoi(arg[1]), arg[2], arg[3], arg[4],
+            &codesize, &datasize, &cachesize, &asecsize);
 
     /*
      * Each int64_t can take up 22 characters printed out. Make sure it
@@ -150,7 +151,7 @@
     { "freecache",            1, do_free_cache },
     { "rmcache",              1, do_rm_cache },
     { "protect",              2, do_protect },
-    { "getsize",              4, do_get_size },
+    { "getsize",              5, do_get_size },
     { "rmuserdata",           2, do_rm_user_data },
     { "movefiles",            0, do_movefiles },
     { "linklib",              2, do_linklib },
@@ -331,37 +332,138 @@
 }
 
 int initialize_directories() {
+    int res = -1;
+    int version = 0;
+    FILE* file;
+
+    // Read current filesystem layout version to handle upgrade paths
+    char version_path[PATH_MAX];
+    if (snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path) > PATH_MAX) {
+        return -1;
+    }
+    file = fopen(version_path, "r");
+    if (file != NULL) {
+        fscanf(file, "%d", &version);
+        fclose(file);
+    }
+
     // /data/user
     char *user_data_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX);
     // /data/data
     char *legacy_data_dir = build_string2(android_data_dir.path, PRIMARY_USER_PREFIX);
     // /data/user/0
-    char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX,
-            "0");
-    int ret = -1;
-    if (user_data_dir != NULL && primary_data_dir != NULL && legacy_data_dir != NULL) {
-        ret = 0;
-        // Make the /data/user directory if necessary
-        if (access(user_data_dir, R_OK) < 0) {
-            if (mkdir(user_data_dir, 0711) < 0) {
-                return -1;
-            }
-            if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) {
-                return -1;
-            }
-            if (chmod(user_data_dir, 0711) < 0) {
-                return -1;
-            }
-        }
-        // Make the /data/user/0 symlink to /data/data if necessary
-        if (access(primary_data_dir, R_OK) < 0) {
-              ret = symlink(legacy_data_dir, primary_data_dir);
-        }
-        free(user_data_dir);
-        free(legacy_data_dir);
-        free(primary_data_dir);
+    char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX, "0");
+    if (!user_data_dir || !legacy_data_dir || !primary_data_dir) {
+        goto fail;
     }
-    return ret;
+
+    // Make the /data/user directory if necessary
+    if (access(user_data_dir, R_OK) < 0) {
+        if (mkdir(user_data_dir, 0711) < 0) {
+            goto fail;
+        }
+        if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) {
+            goto fail;
+        }
+        if (chmod(user_data_dir, 0711) < 0) {
+            goto fail;
+        }
+    }
+    // Make the /data/user/0 symlink to /data/data if necessary
+    if (access(primary_data_dir, R_OK) < 0) {
+        if (symlink(legacy_data_dir, primary_data_dir)) {
+            goto fail;
+        }
+    }
+
+    // /data/media/0
+    char owner_media_dir[PATH_MAX];
+    create_persona_media_path(owner_media_dir, 0);
+
+    if (version == 0) {
+        // Introducing multi-user, so migrate /data/media contents into /data/media/0
+        ALOGD("Migrating /data/media for multi-user");
+
+        // /data/media.tmp
+        char media_tmp_dir[PATH_MAX];
+        snprintf(media_tmp_dir, PATH_MAX, "%smedia.tmp", android_data_dir.path);
+
+        // Only copy when upgrade not already in progress
+        if (access(media_tmp_dir, F_OK) == -1) {
+            if (rename(android_media_dir.path, media_tmp_dir) == -1) {
+                ALOGE("Failed to move legacy media path: %s", strerror(errno));
+                goto fail;
+            }
+        }
+
+        // Create /data/media again
+        if (ensure_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
+            goto fail;
+        }
+
+        // Move any owner data into place
+        if (access(media_tmp_dir, F_OK) == 0) {
+            if (rename(media_tmp_dir, owner_media_dir) == -1) {
+                ALOGE("Failed to move owner media path: %s", strerror(errno));
+                goto fail;
+            }
+        }
+
+        // Ensure media directories for any existing users
+        DIR *dir;
+        struct dirent *dirent;
+        char user_media_dir[PATH_MAX];
+
+        dir = opendir(user_data_dir);
+        if (dir != NULL) {
+            while ((dirent = readdir(dir))) {
+                if (dirent->d_type == DT_DIR) {
+                    const char *name = dirent->d_name;
+
+                    // skip "." and ".."
+                    if (name[0] == '.') {
+                        if (name[1] == 0) continue;
+                        if ((name[1] == '.') && (name[2] == 0)) continue;
+                    }
+
+                    // /data/media/<user_id>
+                    snprintf(user_media_dir, PATH_MAX, "%s%s", android_media_dir.path, name);
+                    if (ensure_dir(user_media_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
+                        ALOGE("Failed to ensure %s: %s", user_media_dir, strerror(errno));
+                        goto fail;
+                    }
+                }
+            }
+            closedir(dir);
+        }
+
+        version = 1;
+    }
+
+    // Ensure /data/media/0 is always ready
+    if (ensure_dir(owner_media_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
+        goto fail;
+    }
+
+    // Persist our current version
+    file = fopen(version_path, "w");
+    if (file != NULL) {
+        fprintf(file, "%d", version);
+        fsync(fileno(file));
+        fclose(file);
+    } else {
+        ALOGE("Failed to save version to %s: %s", version_path, strerror(errno));
+        goto fail;
+    }
+
+    // Success!
+    res = 0;
+
+fail:
+    free(user_data_dir);
+    free(legacy_data_dir);
+    free(primary_data_dir);
+    return res;
 }
 
 int main(const int argc, const char *argv[]) {
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index f5853ff..3201427 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -35,6 +35,7 @@
 #include <cutils/sockets.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
+#include <cutils/multiuser.h>
 
 #include <private/android_filesystem_config.h>
 
@@ -138,6 +139,8 @@
 int create_persona_path(char path[PKG_PATH_MAX],
                     uid_t persona);
 
+int create_persona_media_path(char path[PKG_PATH_MAX], userid_t userid);
+
 int create_move_path(char path[PKG_PATH_MAX],
                      const char* pkgname,
                      const char* leaf,
@@ -180,6 +183,8 @@
 char *build_string2(char *s1, char *s2);
 char *build_string3(char *s1, char *s2, char *s3);
 
+int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
+
 /* commands.c */
 
 int install(const char *pkgname, uid_t uid, gid_t gid);
@@ -194,7 +199,7 @@
 int move_dex(const char *src, const char *dst);
 int rm_dex(const char *path);
 int protect(char *pkgname, gid_t gid);
-int get_size(const char *pkgname, const char *apkpath, const char *fwdlock_apkpath,
+int get_size(const char *pkgname, int persona, const char *apkpath, const char *fwdlock_apkpath,
              const char *asecpath, int64_t *codesize, int64_t *datasize, int64_t *cachesize,
              int64_t *asecsize);
 int free_cache(int64_t free_size);
diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c
index 79db972..80247f1 100644
--- a/cmds/installd/utils.c
+++ b/cmds/installd/utils.c
@@ -137,6 +137,17 @@
     return 0;
 }
 
+/**
+ * Create the path name for media for a certain persona.
+ * Returns 0 on success, and -1 on failure.
+ */
+int create_persona_media_path(char path[PATH_MAX], userid_t userid) {
+    if (snprintf(path, PATH_MAX, "%s%d", android_media_dir.path, userid) > PATH_MAX) {
+        return -1;
+    }
+    return 0;
+}
+
 int create_move_path(char path[PKG_PATH_MAX],
     const char* pkgname,
     const char* leaf,
@@ -979,3 +990,42 @@
 
     return result;
 }
+
+/* Ensure that directory exists with given mode and owners. */
+int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid) {
+    // Check if path needs to be created
+    struct stat sb;
+    if (stat(path, &sb) == -1) {
+        if (errno == ENOENT) {
+            goto create;
+        } else {
+            ALOGE("Failed to stat(%s): %s", path, strerror(errno));
+            return -1;
+        }
+    }
+
+    // Exists, verify status
+    if (sb.st_mode == mode || sb.st_uid == uid || sb.st_gid == gid) {
+        return 0;
+    } else {
+        goto fixup;
+    }
+
+create:
+    if (mkdir(path, mode) == -1) {
+        ALOGE("Failed to mkdir(%s): %s", path, strerror(errno));
+        return -1;
+    }
+
+fixup:
+    if (chown(path, uid, gid) == -1) {
+        ALOGE("Failed to chown(%s, %d, %d): %s", path, uid, gid, strerror(errno));
+        return -1;
+    }
+    if (chmod(path, mode) == -1) {
+        ALOGE("Failed to chown(%s, %d): %s", path, mode, strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index eb1f9a2..b34fd05 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -36,6 +36,7 @@
 import android.content.pm.PermissionGroupInfo;
 import android.content.pm.PermissionInfo;
 import android.content.pm.UserInfo;
+import android.content.pm.VerificationParams;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.net.Uri;
@@ -787,6 +788,8 @@
         String macAlgo = null;
         byte[] macKey = null;
         byte[] tag = null;
+        String originatingUriString = null;
+        String referrer = null;
 
         while ((opt=nextOption()) != null) {
             if (opt.equals("-l")) {
@@ -850,6 +853,20 @@
                     showUsage();
                     return;
                 }
+            } else if (opt.equals("--originating-uri")) {
+                originatingUriString = nextOptionData();
+                if (originatingUriString == null) {
+                    System.err.println("Error: must supply argument for --originating-uri");
+                    showUsage();
+                    return;
+                }
+            } else if (opt.equals("--referrer")) {
+                referrer = nextOptionData();
+                if (referrer == null) {
+                    System.err.println("Error: must supply argument for --referrer");
+                    showUsage();
+                    return;
+                }
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 showUsage();
@@ -897,6 +914,20 @@
 
         final Uri apkURI;
         final Uri verificationURI;
+        final Uri originatingURI;
+        final Uri referrerURI;
+
+        if (originatingUriString != null) {
+            originatingURI = Uri.parse(originatingUriString);
+        } else {
+            originatingURI = null;
+        }
+
+        if (referrer != null) {
+            referrerURI = Uri.parse(referrer);
+        } else {
+            referrerURI = null;
+        }
 
         // Populate apkURI, must be present
         final String apkFilePath = nextArg();
@@ -920,8 +951,11 @@
 
         PackageInstallObserver obs = new PackageInstallObserver();
         try {
-            mPm.installPackageWithVerification(apkURI, obs, installFlags, installerPackageName,
-                    verificationURI, null, encryptionParams);
+            VerificationParams verificationParams = new VerificationParams(verificationURI,
+                    originatingURI, referrerURI, null);
+
+            mPm.installPackageWithVerificationAndEncryption(apkURI, obs, installFlags,
+                    installerPackageName, verificationParams, encryptionParams);
 
             synchronized (obs) {
                 while (!obs.finished) {
@@ -1441,7 +1475,8 @@
         System.err.println("       pm list libraries");
         System.err.println("       pm path PACKAGE");
         System.err.println("       pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f]");
-        System.err.println("                  [--algo <algorithm name> --key <key-in-hex> --iv <IV-in-hex>] PATH");
+        System.err.println("                  [--algo <algorithm name> --key <key-in-hex> --iv <IV-in-hex>]");
+        System.err.println("                  [--originating-uri <URI>] [--referrer <URI>] PATH");
         System.err.println("       pm uninstall [-k] PACKAGE");
         System.err.println("       pm clear PACKAGE");
         System.err.println("       pm enable PACKAGE_OR_COMPONENT");
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index e1d6619..ec3ec3e 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -37,7 +37,7 @@
     public String longHelp() {
         return shortHelp() + "\n"
                 + "\n"
-                + "usage: svc power stayon [true|false|usb|ac]\n"
+                + "usage: svc power stayon [true|false|usb|ac|wireless]\n"
                 + "         Set the 'keep awake while plugged in' setting.\n";
     }
 
@@ -48,7 +48,8 @@
                     int val;
                     if ("true".equals(args[2])) {
                         val = BatteryManager.BATTERY_PLUGGED_AC |
-                                BatteryManager.BATTERY_PLUGGED_USB;
+                                BatteryManager.BATTERY_PLUGGED_USB |
+                                BatteryManager.BATTERY_PLUGGED_WIRELESS;
                     }
                     else if ("false".equals(args[2])) {
                         val = 0;
@@ -56,15 +57,16 @@
                         val = BatteryManager.BATTERY_PLUGGED_USB;
                     } else if ("ac".equals(args[2])) {
                         val = BatteryManager.BATTERY_PLUGGED_AC;
-                    }
-                    else {
+                    } else if ("wireless".equals(args[2])) {
+                        val = BatteryManager.BATTERY_PLUGGED_WIRELESS;
+                    } else {
                         break fail;
                     }
                     IPowerManager pm
                             = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE));
                     try {
                         IBinder lock = new Binder();
-                        pm.acquireWakeLock(PowerManager.FULL_WAKE_LOCK, lock, "svc power", null);
+                        pm.acquireWakeLock(lock, PowerManager.FULL_WAKE_LOCK, "svc power", null);
                         pm.setStayOnSetting(val);
                         pm.releaseWakeLock(lock, 0);
                     }
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 935d647..7a9f285 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -50,7 +50,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -354,7 +354,7 @@
     }
 
     private UserAccounts getUserAccountsForCaller() {
-        return getUserAccounts(UserId.getCallingUserId());
+        return getUserAccounts(UserHandle.getCallingUserId());
     }
 
     protected UserAccounts getUserAccounts(int userId) {
@@ -369,7 +369,7 @@
     }
 
     private void onUserRemoved(Intent intent) {
-        int userId = intent.getIntExtra(Intent.EXTRA_USERID, -1);
+        int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
         if (userId < 1) return;
 
         UserAccounts accounts;
@@ -900,7 +900,7 @@
     private void sendAccountsChangedBroadcast(int userId) {
         Log.i(TAG, "the accounts changed, sending broadcast of "
                 + ACCOUNTS_CHANGED_INTENT.getAction());
-        mContext.sendBroadcastToUser(ACCOUNTS_CHANGED_INTENT, userId);
+        mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
     }
 
     public void clearPassword(Account account) {
@@ -1004,7 +1004,7 @@
         if (callingUid != android.os.Process.SYSTEM_UID) {
             throw new SecurityException("can only call from system");
         }
-        UserAccounts accounts = getUserAccounts(UserId.getUserId(callingUid));
+        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
         long identityToken = clearCallingIdentity();
         try {
             new Session(accounts, response, accountType, false,
@@ -1222,7 +1222,7 @@
     private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
             int uid) {
         Integer id;
-        UserAccounts accounts = getUserAccounts(UserId.getUserId(uid));
+        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
         synchronized (accounts.credentialsPermissionNotificationIds) {
             final Pair<Pair<Account, String>, Integer> key =
                     new Pair<Pair<Account, String>, Integer>(
@@ -2269,7 +2269,7 @@
             Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
             return;
         }
-        UserAccounts accounts = getUserAccounts(UserId.getUserId(uid));
+        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
         synchronized (accounts.cacheLock) {
             final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
             db.beginTransaction();
@@ -2303,7 +2303,7 @@
             Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
             return;
         }
-        UserAccounts accounts = getUserAccounts(UserId.getUserId(uid));
+        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
         synchronized (accounts.cacheLock) {
             final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
             db.beginTransaction();
diff --git a/core/java/android/animation/TimeAnimator.java b/core/java/android/animation/TimeAnimator.java
index 088d20d..f9aa00e 100644
--- a/core/java/android/animation/TimeAnimator.java
+++ b/core/java/android/animation/TimeAnimator.java
@@ -13,6 +13,12 @@
     private long mPreviousTime = -1;
 
     @Override
+    public void start() {
+        mPreviousTime = -1;
+        super.start();
+    }
+
+    @Override
     boolean animationFrame(long currentTime) {
         if (mListener != null) {
             long totalTime = currentTime - mStartTime;
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index f3a442a..f874d56 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -232,6 +232,13 @@
     }
 
     /**
+     * @hide
+     */
+    public static float getDurationScale() {
+        return sDurationScale;
+    }
+
+    /**
      * Creates a new ValueAnimator object. This default constructor is primarily for
      * use internally; the factory methods which take parameters are more generally
      * useful.
@@ -529,6 +536,9 @@
         // The per-thread list of all active animations
         private final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();
 
+        // Used in doAnimationFrame() to avoid concurrent modifications of mAnimations
+        private final ArrayList<ValueAnimator> mTmpAnimations = new ArrayList<ValueAnimator>();
+
         // The per-thread set of animations to be started on the next animation frame
         private final ArrayList<ValueAnimator> mPendingAnimations = new ArrayList<ValueAnimator>();
 
@@ -598,28 +608,18 @@
             // Now process all active animations. The return value from animationFrame()
             // tells the handler whether it should now be ended
             int numAnims = mAnimations.size();
-            int i = 0;
-            while (i < numAnims) {
-                ValueAnimator anim = mAnimations.get(i);
-                if (anim.doAnimationFrame(frameTime)) {
+            for (int i = 0; i < numAnims; ++i) {
+                mTmpAnimations.add(mAnimations.get(i));
+            }
+            for (int i = 0; i < numAnims; ++i) {
+                ValueAnimator anim = mTmpAnimations.get(i);
+                if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) {
                     mEndingAnims.add(anim);
                 }
-                if (mAnimations.size() == numAnims) {
-                    ++i;
-                } else {
-                    // An animation might be canceled or ended by client code
-                    // during the animation frame. Check to see if this happened by
-                    // seeing whether the current index is the same as it was before
-                    // calling animationFrame(). Another approach would be to copy
-                    // animations to a temporary list and process that list instead,
-                    // but that entails garbage and processing overhead that would
-                    // be nice to avoid.
-                    --numAnims;
-                    mEndingAnims.remove(anim);
-                }
             }
+            mTmpAnimations.clear();
             if (mEndingAnims.size() > 0) {
-                for (i = 0; i < mEndingAnims.size(); ++i) {
+                for (int i = 0; i < mEndingAnims.size(); ++i) {
                     mEndingAnims.get(i).endAnimation(this);
                 }
                 mEndingAnims.clear();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 809acac..395a79c 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -74,7 +74,7 @@
 import android.view.ViewManager;
 import android.view.Window;
 import android.view.WindowManager;
-import android.view.WindowManagerImpl;
+import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.AdapterView;
 
@@ -4733,6 +4733,29 @@
             mLoaderManager.dump(prefix + "  ", fd, writer, args);
         }
         mFragments.dump(prefix, fd, writer, args);
+        writer.print(prefix); writer.println("View Hierarchy:");
+        dumpViewHierarchy(prefix + "  ", writer, getWindow().getDecorView());
+    }
+
+    private void dumpViewHierarchy(String prefix, PrintWriter writer, View view) {
+        writer.print(prefix);
+        if (view == null) {
+            writer.println("null");
+            return;
+        }
+        writer.println(view.toString());
+        if (!(view instanceof ViewGroup)) {
+            return;
+        }
+        ViewGroup grp = (ViewGroup)view;
+        final int N = grp.getChildCount();
+        if (N <= 0) {
+            return;
+        }
+        prefix = prefix + "  ";
+        for (int i=0; i<N; i++) {
+            dumpViewHierarchy(prefix, writer, grp.getChildAt(i));
+        }
     }
 
     /**
@@ -4995,7 +5018,9 @@
         mEmbeddedID = id;
         mLastNonConfigurationInstances = lastNonConfigurationInstances;
 
-        mWindow.setWindowManager(null, mToken, mComponent.flattenToString(),
+        mWindow.setWindowManager(
+                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
+                mToken, mComponent.flattenToString(),
                 (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
         if (mParent != null) {
             mWindow.setContainer(mParent.getWindow());
@@ -5042,7 +5067,7 @@
         if (mStopped) {
             mStopped = false;
             if (mToken != null && mParent == null) {
-                WindowManagerImpl.getDefault().setStoppedState(mToken, false);
+                WindowManagerGlobal.getInstance().setStoppedState(mToken, false);
             }
 
             synchronized (mManagedCursors) {
@@ -5142,7 +5167,7 @@
             }
 
             if (mToken != null && mParent == null) {
-                WindowManagerImpl.getDefault().setStoppedState(mToken, true);
+                WindowManagerGlobal.getInstance().setStoppedState(mToken, true);
             }
             
             mFragments.dispatchStop();
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index c74f823..e644db4 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -30,6 +30,7 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Point;
+import android.hardware.display.DisplayManager;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Debug;
@@ -40,7 +41,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -366,7 +367,7 @@
      * (which tends to consume a lot more RAM).
      * @hide
      */
-    static public boolean isHighEndGfx(Display display) {
+    static public boolean isHighEndGfx() {
         MemInfoReader reader = new MemInfoReader();
         reader.readMemInfo();
         if (reader.getTotalSize() >= (512*1024*1024)) {
@@ -374,6 +375,8 @@
             // we can afford the overhead of graphics acceleration.
             return true;
         }
+
+        Display display = DisplayManager.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
         Point p = new Point();
         display.getRealSize(p);
         int pixels = p.x * p.y;
@@ -529,7 +532,7 @@
             throws SecurityException {
         try {
             return ActivityManagerNative.getDefault().getRecentTasks(maxNum,
-                    flags, UserId.myUserId());
+                    flags, UserHandle.myUserId());
         } catch (RemoteException e) {
             // System dead, we will be dead too soon!
             return null;
@@ -1375,6 +1378,13 @@
         public static final int FLAG_PERSISTENT = 1<<1;
 
         /**
+         * Constant for {@link #flags}: this process is associated with a
+         * persistent system app.
+         * @hide
+         */
+        public static final int FLAG_HAS_ACTIVITIES = 1<<2;
+
+        /**
          * Flags of information.  May be any of
          * {@link #FLAG_CANT_SAVE_STATE}.
          * @hide
@@ -1843,12 +1853,12 @@
             return PackageManager.PERMISSION_GRANTED;
         }
         // Isolated processes don't get any permissions.
-        if (UserId.isIsolated(uid)) {
+        if (UserHandle.isIsolated(uid)) {
             return PackageManager.PERMISSION_DENIED;
         }
         // If there is a uid that owns whatever is being accessed, it has
         // blanket access to it regardless of the permissions it requires.
-        if (owningUid >= 0 && UserId.isSameApp(uid, owningUid)) {
+        if (owningUid >= 0 && UserHandle.isSameApp(uid, owningUid)) {
             return PackageManager.PERMISSION_GRANTED;
         }
         // If the target is not exported, then nobody else can get to it.
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 88e7344..3197a63 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -39,7 +39,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StrictMode;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Singleton;
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 4edfdfb..87b1e24 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -97,9 +97,9 @@
     /** @hide */
     public static final int ANIM_SCALE_UP = 2;
     /** @hide */
-    public static final int ANIM_THUMBNAIL = 3;
+    public static final int ANIM_THUMBNAIL_SCALE_UP = 3;
     /** @hide */
-    public static final int ANIM_THUMBNAIL_DELAYED = 4;
+    public static final int ANIM_THUMBNAIL_SCALE_DOWN = 4;
 
     private String mPackageName;
     private int mAnimationType = ANIM_NONE;
@@ -262,20 +262,19 @@
      */
     public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
-        return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, listener, false);
+        return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true);
     }
 
     /**
-     * Create an ActivityOptions specifying an animation where a thumbnail
-     * is scaled from a given position to the new activity window that is
-     * being started. Before the animation, there is a short delay.
+     * Create an ActivityOptions specifying an animation where an activity window
+     * is scaled from a given position to a thumbnail at a specified location.
      *
-     * @param source The View that this thumbnail is animating from.  This
+     * @param source The View that this thumbnail is animating to.  This
      * defines the coordinate space for <var>startX</var> and <var>startY</var>.
-     * @param thumbnail The bitmap that will be shown as the initial thumbnail
+     * @param thumbnail The bitmap that will be shown as the final thumbnail
      * of the animation.
-     * @param startX The x starting location of the bitmap, relative to <var>source</var>.
-     * @param startY The y starting location of the bitmap, relative to <var>source</var>.
+     * @param startX The x end location of the bitmap, relative to <var>source</var>.
+     * @param startY The y end location of the bitmap, relative to <var>source</var>.
      * @param listener Optional OnAnimationStartedListener to find out when the
      * requested animation has started running.  If for some reason the animation
      * is not executed, the callback will happen immediately.
@@ -283,17 +282,17 @@
      * supply these options as the options Bundle when starting an activity.
      * @hide
      */
-    public static ActivityOptions makeDelayedThumbnailScaleUpAnimation(View source,
+    public static ActivityOptions makeThumbnailScaleDownAnimation(View source,
             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
-        return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, listener, true);
+        return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, false);
     }
 
-    private static ActivityOptions makeThumbnailScaleUpAnimation(View source,
+    private static ActivityOptions makeThumbnailAnimation(View source,
             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
-            boolean delayed) {
+            boolean scaleUp) {
         ActivityOptions opts = new ActivityOptions();
         opts.mPackageName = source.getContext().getPackageName();
-        opts.mAnimationType = delayed ? ANIM_THUMBNAIL_DELAYED : ANIM_THUMBNAIL;
+        opts.mAnimationType = scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN;
         opts.mThumbnail = thumbnail;
         int[] pts = new int[2];
         source.getLocationOnScreen(pts);
@@ -320,8 +319,8 @@
             mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
             mStartWidth = opts.getInt(KEY_ANIM_START_WIDTH, 0);
             mStartHeight = opts.getInt(KEY_ANIM_START_HEIGHT, 0);
-        } else if (mAnimationType == ANIM_THUMBNAIL ||
-                mAnimationType == ANIM_THUMBNAIL_DELAYED) {
+        } else if (mAnimationType == ANIM_THUMBNAIL_SCALE_UP ||
+                mAnimationType == ANIM_THUMBNAIL_SCALE_DOWN) {
             mThumbnail = (Bitmap)opts.getParcelable(KEY_ANIM_THUMBNAIL);
             mStartX = opts.getInt(KEY_ANIM_START_X, 0);
             mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
@@ -434,8 +433,8 @@
                 }
                 mAnimationStartedListener = null;
                 break;
-            case ANIM_THUMBNAIL:
-            case ANIM_THUMBNAIL_DELAYED:
+            case ANIM_THUMBNAIL_SCALE_UP:
+            case ANIM_THUMBNAIL_SCALE_DOWN:
                 mAnimationType = otherOptions.mAnimationType;
                 mThumbnail = otherOptions.mThumbnail;
                 mStartX = otherOptions.mStartX;
@@ -479,8 +478,8 @@
                 b.putInt(KEY_ANIM_START_WIDTH, mStartWidth);
                 b.putInt(KEY_ANIM_START_HEIGHT, mStartHeight);
                 break;
-            case ANIM_THUMBNAIL:
-            case ANIM_THUMBNAIL_DELAYED:
+            case ANIM_THUMBNAIL_SCALE_UP:
+            case ANIM_THUMBNAIL_SCALE_DOWN:
                 b.putInt(KEY_ANIM_TYPE, mAnimationType);
                 b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail);
                 b.putInt(KEY_ANIM_START_X, mStartX);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index bb35ddd..28c5abd 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -42,6 +42,7 @@
 import android.database.sqlite.SQLiteDebug.DbStats;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.hardware.display.DisplayManager;
 import android.net.IConnectivityManager;
 import android.net.Proxy;
 import android.net.ProxyProperties;
@@ -62,7 +63,7 @@
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.Trace;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.AndroidRuntimeException;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
@@ -79,8 +80,9 @@
 import android.view.ViewRootImpl;
 import android.view.Window;
 import android.view.WindowManager;
-import android.view.WindowManagerImpl;
+import android.view.WindowManagerGlobal;
 import android.renderscript.RenderScript;
+import android.security.AndroidKeyStoreProvider;
 
 import com.android.internal.os.BinderInternal;
 import com.android.internal.os.RuntimeInit;
@@ -95,6 +97,7 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.net.InetAddress;
+import java.security.Security;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -1055,7 +1058,7 @@
         @Override
         public void dumpGfxInfo(FileDescriptor fd, String[] args) {
             dumpGraphicsInfo(fd);
-            WindowManagerImpl.getDefault().dumpGfxInfo(fd);
+            WindowManagerGlobal.getInstance().dumpGfxInfo(fd);
         }
 
         @Override
@@ -1471,13 +1474,25 @@
 
     private static class ResourcesKey {
         final private String mResDir;
+        final private Configuration mOverrideConfiguration;
         final private float mScale;
         final private int mHash;
 
-        ResourcesKey(String resDir, float scale) {
+        ResourcesKey(String resDir, Configuration overrideConfiguration, float scale) {
             mResDir = resDir;
+            if (overrideConfiguration != null) {
+                if (Configuration.EMPTY.equals(overrideConfiguration)) {
+                    overrideConfiguration = null;
+                }
+            }
+            mOverrideConfiguration = overrideConfiguration;
             mScale = scale;
-            mHash = mResDir.hashCode() << 2 + (int) (mScale * 2);
+            int hash = 17;
+            hash = 31 * hash + mResDir.hashCode();
+            hash = 31 * hash + (mOverrideConfiguration != null
+                    ? mOverrideConfiguration.hashCode() : 0);
+            hash = 31 * hash + Float.floatToIntBits(mScale);
+            mHash = hash;
         }
 
         @Override
@@ -1491,7 +1506,21 @@
                 return false;
             }
             ResourcesKey peer = (ResourcesKey) obj;
-            return mResDir.equals(peer.mResDir) && mScale == peer.mScale;
+            if (!mResDir.equals(peer.mResDir)) {
+                return false;
+            }
+            if (mOverrideConfiguration != peer.mOverrideConfiguration) {
+                if (mOverrideConfiguration == null || peer.mOverrideConfiguration == null) {
+                    return false;
+                }
+                if (!mOverrideConfiguration.equals(peer.mOverrideConfiguration)) {
+                    return false;
+                }
+            }
+            if (mScale != peer.mScale) {
+                return false;
+            }
+            return true;
         }
     }
 
@@ -1527,13 +1556,23 @@
         if (dm != null && !forceUpdate) {
             return dm;
         }
+
+        DisplayManager displayManager = DisplayManager.getInstance();
+        if (displayManager == null) {
+            // may be null early in system startup
+            dm = new DisplayMetrics();
+            dm.setToDefaults();
+            return dm;
+        }
+
         if (dm == null) {
             dm = new DisplayMetrics();
             mDisplayMetrics.put(ci, dm);
         }
+
         CompatibilityInfoHolder cih = new CompatibilityInfoHolder();
         cih.set(ci);
-        Display d = WindowManagerImpl.getDefault().makeCompatible(cih).getDefaultDisplay();
+        Display d = displayManager.getCompatibleDisplay(Display.DEFAULT_DISPLAY, cih);
         d.getMetrics(dm);
         //Slog.i("foo", "New metrics: w=" + metrics.widthPixels + " h="
         //        + metrics.heightPixels + " den=" + metrics.density
@@ -1562,8 +1601,10 @@
      * @param compInfo the compability info. It will use the default compatibility info when it's
      * null.
      */
-    Resources getTopLevelResources(String resDir, CompatibilityInfo compInfo) {
-        ResourcesKey key = new ResourcesKey(resDir, compInfo.applicationScale);
+    Resources getTopLevelResources(String resDir, Configuration overrideConfiguration,
+            CompatibilityInfo compInfo) {
+        ResourcesKey key = new ResourcesKey(resDir, overrideConfiguration,
+                compInfo.applicationScale);
         Resources r;
         synchronized (mPackages) {
             // Resources is app scale dependent.
@@ -1595,13 +1636,20 @@
 
         //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
         DisplayMetrics metrics = getDisplayMetricsLocked(null, false);
-        r = new Resources(assets, metrics, getConfiguration(), compInfo);
+        Configuration config;
+        if (key.mOverrideConfiguration != null) {
+            config = new Configuration(getConfiguration());
+            config.updateFrom(key.mOverrideConfiguration);
+        } else {
+            config = getConfiguration();
+        }
+        r = new Resources(assets, metrics, config, compInfo);
         if (false) {
             Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
                     + r.getConfiguration() + " appScale="
                     + r.getCompatibilityInfo().applicationScale);
         }
-        
+
         synchronized (mPackages) {
             WeakReference<Resources> wr = mActiveResources.get(key);
             Resources existing = wr != null ? wr.get() : null;
@@ -1621,8 +1669,10 @@
     /**
      * Creates the top level resources for the given package.
      */
-    Resources getTopLevelResources(String resDir, LoadedApk pkgInfo) {
-        return getTopLevelResources(resDir, pkgInfo.mCompatibilityInfo.get());
+    Resources getTopLevelResources(String resDir, Configuration overrideConfiguration,
+            LoadedApk pkgInfo) {
+        return getTopLevelResources(resDir, overrideConfiguration,
+                pkgInfo.mCompatibilityInfo.get());
     }
 
     final Handler getHandler() {
@@ -1659,7 +1709,7 @@
         ApplicationInfo ai = null;
         try {
             ai = getPackageManager().getApplicationInfo(packageName,
-                    PackageManager.GET_SHARED_LIBRARY_FILES, UserId.myUserId());
+                    PackageManager.GET_SHARED_LIBRARY_FILES, UserHandle.myUserId());
         } catch (RemoteException e) {
             // Ignore
         }
@@ -1676,7 +1726,7 @@
         boolean includeCode = (flags&Context.CONTEXT_INCLUDE_CODE) != 0;
         boolean securityViolation = includeCode && ai.uid != 0
                 && ai.uid != Process.SYSTEM_UID && (mBoundApplication != null
-                        ? !UserId.isSameApp(ai.uid, mBoundApplication.appInfo.uid)
+                        ? !UserHandle.isSameApp(ai.uid, mBoundApplication.appInfo.uid)
                         : true);
         if ((flags&(Context.CONTEXT_INCLUDE_CODE
                 |Context.CONTEXT_IGNORE_SECURITY))
@@ -2594,7 +2644,7 @@
             r.mPendingRemoveWindowManager.removeViewImmediate(r.mPendingRemoveWindow);
             IBinder wtoken = r.mPendingRemoveWindow.getWindowToken();
             if (wtoken != null) {
-                WindowManagerImpl.getDefault().closeAll(wtoken,
+                WindowManagerGlobal.getInstance().closeAll(wtoken,
                         r.activity.getClass().getName(), "Activity");
             }
         }
@@ -3129,7 +3179,7 @@
             apk.mCompatibilityInfo.set(data.info);
         }
         handleConfigurationChanged(mConfiguration, data.info);
-        WindowManagerImpl.getDefault().reportNewConfiguration(mConfiguration);
+        WindowManagerGlobal.getInstance().reportNewConfiguration(mConfiguration);
     }
 
     private void deliverResults(ActivityClientRecord r, List<ResultInfo> results) {
@@ -3318,7 +3368,7 @@
                     }
                 }
                 if (wtoken != null && r.mPendingRemoveWindow == null) {
-                    WindowManagerImpl.getDefault().closeAll(wtoken,
+                    WindowManagerGlobal.getInstance().closeAll(wtoken,
                             r.activity.getClass().getName(), "Activity");
                 }
                 r.activity.mDecor = null;
@@ -3330,7 +3380,7 @@
                 // by the app will leak.  Well we try to warning them a lot
                 // about leaking windows, because that is a bug, so if they are
                 // using this recreate facility then they get to live with leaks.
-                WindowManagerImpl.getDefault().closeAll(token,
+                WindowManagerGlobal.getInstance().closeAll(token,
                         r.activity.getClass().getName(), "Activity");
             }
 
@@ -3675,18 +3725,28 @@
 
         ApplicationPackageManager.configurationChanged();
         //Slog.i(TAG, "Configuration changed in " + currentPackageName());
-        
-        Iterator<WeakReference<Resources>> it =
-            mActiveResources.values().iterator();
-        //Iterator<Map.Entry<String, WeakReference<Resources>>> it =
-        //    mActiveResources.entrySet().iterator();
+
+        Configuration tmpConfig = null;
+
+        Iterator<Map.Entry<ResourcesKey, WeakReference<Resources>>> it =
+                mActiveResources.entrySet().iterator();
         while (it.hasNext()) {
-            WeakReference<Resources> v = it.next();
-            Resources r = v.get();
+            Map.Entry<ResourcesKey, WeakReference<Resources>> entry = it.next();
+            Resources r = entry.getValue().get();
             if (r != null) {
                 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
                         + r + " config to: " + config);
-                r.updateConfiguration(config, dm, compat);
+                Configuration override = entry.getKey().mOverrideConfiguration;
+                if (override != null) {
+                    if (tmpConfig == null) {
+                        tmpConfig = new Configuration();
+                    }
+                    tmpConfig.setTo(config);
+                    tmpConfig.updateFrom(override);
+                    r.updateConfiguration(tmpConfig, dm, compat);
+                } else {
+                    r.updateConfiguration(config, dm, compat);
+                }
                 //Slog.i(TAG, "Updated app resources " + v.getKey()
                 //        + " " + r + ": " + r.getConfiguration());
             } else {
@@ -3748,7 +3808,7 @@
         }
         
         // Cleanup hardware accelerated stuff
-        WindowManagerImpl.getDefault().trimLocalMemory();
+        WindowManagerGlobal.getInstance().trimLocalMemory();
 
         freeTextLayoutCachesIfNeeded(configDiff);
 
@@ -3888,7 +3948,7 @@
     final void handleTrimMemory(int level) {
         if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Trimming memory to level: " + level);
 
-        final WindowManagerImpl windowManager = WindowManagerImpl.getDefault();
+        final WindowManagerGlobal windowManager = WindowManagerGlobal.getInstance();
         windowManager.startTrimMemory(level);
 
         ArrayList<ComponentCallbacks2> callbacks;
@@ -3901,7 +3961,7 @@
             callbacks.get(i).onTrimMemory(level);
         }
 
-        windowManager.endTrimMemory();        
+        windowManager.endTrimMemory();
     }
 
     private void setupGraphicsSupport(LoadedApk info, File cacheDir) {
@@ -3954,8 +4014,7 @@
             // Persistent processes on low-memory devices do not get to
             // use hardware accelerated drawing, since this can add too much
             // overhead to the process.
-            final Display display = WindowManagerImpl.getDefault().getDefaultDisplay();
-            if (!ActivityManager.isHighEndGfx(display)) {
+            if (!ActivityManager.isHighEndGfx()) {
                 HardwareRenderer.disable(false);
             }
         }
@@ -4008,13 +4067,14 @@
 
         final ContextImpl appContext = new ContextImpl();
         appContext.init(data.info, null, this);
-        final File cacheDir = appContext.getCacheDir();
+        if (!Process.isIsolated()) {
+            final File cacheDir = appContext.getCacheDir();
 
-        // Provide a usable directory for temporary files
-        System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
+            // Provide a usable directory for temporary files
+            System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
 
-        setupGraphicsSupport(data.info, cacheDir);
-
+            setupGraphicsSupport(data.info, cacheDir);
+        }
         /**
          * For system applications on userdebug/eng builds, log stack
          * traces of disk and network access to dropbox for analysis.
@@ -4752,16 +4812,19 @@
         // StrictMode) on debug builds, but using DropBox, not logs.
         CloseGuard.setEnabled(false);
 
+        Security.addProvider(new AndroidKeyStoreProvider());
+
         Process.setArgV0("<pre-initialized>");
 
         Looper.prepareMainLooper();
-        if (sMainThreadHandler == null) {
-            sMainThreadHandler = new Handler();
-        }
 
         ActivityThread thread = new ActivityThread();
         thread.attach(false);
 
+        if (sMainThreadHandler == null) {
+            sMainThreadHandler = thread.getHandler();
+        }
+
         AsyncTask.init();
 
         if (false) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 2face4c..86ee8a0 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -43,6 +43,7 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.ManifestDigest;
 import android.content.pm.UserInfo;
+import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -50,7 +51,7 @@
 import android.net.Uri;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.Log;
 
 import java.lang.ref.WeakReference;
@@ -69,7 +70,7 @@
     public PackageInfo getPackageInfo(String packageName, int flags)
             throws NameNotFoundException {
         try {
-            PackageInfo pi = mPM.getPackageInfo(packageName, flags, UserId.myUserId());
+            PackageInfo pi = mPM.getPackageInfo(packageName, flags, UserHandle.myUserId());
             if (pi != null) {
                 return pi;
             }
@@ -199,7 +200,7 @@
     public ApplicationInfo getApplicationInfo(String packageName, int flags)
             throws NameNotFoundException {
         try {
-            ApplicationInfo ai = mPM.getApplicationInfo(packageName, flags, UserId.myUserId());
+            ApplicationInfo ai = mPM.getApplicationInfo(packageName, flags, UserHandle.myUserId());
             if (ai != null) {
                 return ai;
             }
@@ -214,7 +215,7 @@
     public ActivityInfo getActivityInfo(ComponentName className, int flags)
             throws NameNotFoundException {
         try {
-            ActivityInfo ai = mPM.getActivityInfo(className, flags, UserId.myUserId());
+            ActivityInfo ai = mPM.getActivityInfo(className, flags, UserHandle.myUserId());
             if (ai != null) {
                 return ai;
             }
@@ -229,7 +230,7 @@
     public ActivityInfo getReceiverInfo(ComponentName className, int flags)
             throws NameNotFoundException {
         try {
-            ActivityInfo ai = mPM.getReceiverInfo(className, flags, UserId.myUserId());
+            ActivityInfo ai = mPM.getReceiverInfo(className, flags, UserHandle.myUserId());
             if (ai != null) {
                 return ai;
             }
@@ -244,7 +245,7 @@
     public ServiceInfo getServiceInfo(ComponentName className, int flags)
             throws NameNotFoundException {
         try {
-            ServiceInfo si = mPM.getServiceInfo(className, flags, UserId.myUserId());
+            ServiceInfo si = mPM.getServiceInfo(className, flags, UserHandle.myUserId());
             if (si != null) {
                 return si;
             }
@@ -259,7 +260,7 @@
     public ProviderInfo getProviderInfo(ComponentName className, int flags)
             throws NameNotFoundException {
         try {
-            ProviderInfo pi = mPM.getProviderInfo(className, flags, UserId.myUserId());
+            ProviderInfo pi = mPM.getProviderInfo(className, flags, UserHandle.myUserId());
             if (pi != null) {
                 return pi;
             }
@@ -424,7 +425,7 @@
     @SuppressWarnings("unchecked")
     @Override
     public List<ApplicationInfo> getInstalledApplications(int flags) {
-        int userId = UserId.getUserId(Process.myUid());
+        int userId = UserHandle.getUserId(Process.myUid());
         try {
             final List<ApplicationInfo> applicationInfos = new ArrayList<ApplicationInfo>();
             ApplicationInfo lastItem = null;
@@ -448,7 +449,7 @@
             return mPM.resolveIntent(
                 intent,
                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
-                    flags, UserId.myUserId());
+                    flags, UserHandle.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -462,7 +463,7 @@
                 intent,
                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                 flags,
-                UserId.myUserId());
+                UserHandle.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -494,7 +495,7 @@
         try {
             return mPM.queryIntentActivityOptions(caller, specifics,
                                                   specificTypes, intent, intent.resolveTypeIfNeeded(resolver),
-                                                  flags, UserId.myUserId());
+                                                  flags, UserHandle.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -507,7 +508,7 @@
                 intent,
                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                 flags,
-                UserId.myUserId());
+                UserHandle.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -520,7 +521,7 @@
                 intent,
                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                 flags,
-                UserId.myUserId());
+                UserHandle.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -533,7 +534,7 @@
                 intent,
                 intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                 flags,
-                UserId.myUserId());
+                UserHandle.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -543,7 +544,7 @@
     public ProviderInfo resolveContentProvider(String name,
                                                int flags) {
         try {
-            return mPM.resolveContentProvider(name, flags, UserId.myUserId());
+            return mPM.resolveContentProvider(name, flags, UserHandle.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException("Package manager has died", e);
         }
@@ -713,7 +714,7 @@
         }
         Resources r = mContext.mMainThread.getTopLevelResources(
             app.uid == Process.myUid() ? app.sourceDir
-            : app.publicSourceDir, mContext.mPackageInfo);
+            : app.publicSourceDir, null, mContext.mPackageInfo);
         if (r != null) {
             return r;
         }
@@ -984,6 +985,18 @@
     }
 
     @Override
+	  public void installPackageWithVerificationAndEncryption(Uri packageURI,
+            IPackageInstallObserver observer, int flags, String installerPackageName,
+            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
+        try {
+            mPM.installPackageWithVerificationAndEncryption(packageURI, observer, flags,
+                    installerPackageName, verificationParams, encryptionParams);
+        } catch (RemoteException e) {
+            // Should never happen!
+        }
+    }
+
+    @Override
     public void verifyPendingInstall(int id, int response) {
         try {
             mPM.verifyPendingInstall(id, response);
@@ -1033,7 +1046,7 @@
     public void clearApplicationUserData(String packageName,
                                          IPackageDataObserver observer) {
         try {
-            mPM.clearApplicationUserData(packageName, observer, UserId.myUserId());
+            mPM.clearApplicationUserData(packageName, observer, UserHandle.myUserId());
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1066,10 +1079,10 @@
     }
 
     @Override
-    public void getPackageSizeInfo(String packageName,
-                                   IPackageStatsObserver observer) {
+    public void getPackageSizeInfo(String packageName, int userHandle,
+            IPackageStatsObserver observer) {
         try {
-            mPM.getPackageSizeInfo(packageName, observer);
+            mPM.getPackageSizeInfo(packageName, userHandle, observer);
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1106,7 +1119,17 @@
     public void addPreferredActivity(IntentFilter filter,
                                      int match, ComponentName[] set, ComponentName activity) {
         try {
-            mPM.addPreferredActivity(filter, match, set, activity);
+            mPM.addPreferredActivity(filter, match, set, activity, UserHandle.myUserId());
+        } catch (RemoteException e) {
+            // Should never happen!
+        }
+    }
+
+    @Override
+    public void addPreferredActivity(IntentFilter filter, int match,
+            ComponentName[] set, ComponentName activity, int userId) {
+        try {
+            mPM.addPreferredActivity(filter, match, set, activity, userId);
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1146,7 +1169,7 @@
     public void setComponentEnabledSetting(ComponentName componentName,
                                            int newState, int flags) {
         try {
-            mPM.setComponentEnabledSetting(componentName, newState, flags, UserId.myUserId());
+            mPM.setComponentEnabledSetting(componentName, newState, flags, UserHandle.myUserId());
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1155,7 +1178,7 @@
     @Override
     public int getComponentEnabledSetting(ComponentName componentName) {
         try {
-            return mPM.getComponentEnabledSetting(componentName, UserId.myUserId());
+            return mPM.getComponentEnabledSetting(componentName, UserHandle.myUserId());
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1166,7 +1189,7 @@
     public void setApplicationEnabledSetting(String packageName,
                                              int newState, int flags) {
         try {
-            mPM.setApplicationEnabledSetting(packageName, newState, flags, UserId.myUserId());
+            mPM.setApplicationEnabledSetting(packageName, newState, flags, UserHandle.myUserId());
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1175,7 +1198,7 @@
     @Override
     public int getApplicationEnabledSetting(String packageName) {
         try {
-            return mPM.getApplicationEnabledSetting(packageName, UserId.myUserId());
+            return mPM.getApplicationEnabledSetting(packageName, UserHandle.myUserId());
         } catch (RemoteException e) {
             // Should never happen!
         }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4496ce8..0543f05 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -37,6 +37,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
 import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
@@ -86,7 +87,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.os.SystemVibrator;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
@@ -94,7 +95,9 @@
 import android.content.ClipboardManager;
 import android.util.AndroidRuntimeException;
 import android.util.Log;
+import android.view.CompatibilityInfoHolder;
 import android.view.ContextThemeWrapper;
+import android.view.Display;
 import android.view.WindowManagerImpl;
 import android.view.accessibility.AccessibilityManager;
 import android.view.inputmethod.InputMethodManager;
@@ -417,7 +420,8 @@
                 public Object createService(ContextImpl ctx) {
                     IBinder b = ServiceManager.getService(POWER_SERVICE);
                     IPowerManager service = IPowerManager.Stub.asInterface(b);
-                    return new PowerManager(service, ctx.mMainThread.getHandler());
+                    return new PowerManager(ctx.getOuterContext(),
+                            service, ctx.mMainThread.getHandler());
                 }});
 
         registerService(SEARCH_SERVICE, new ServiceFetcher() {
@@ -497,8 +501,8 @@
 
         registerService(WINDOW_SERVICE, new ServiceFetcher() {
                 public Object getService(ContextImpl ctx) {
-                    return WindowManagerImpl.getDefault().makeCompatible(
-                            ctx.mPackageInfo.mCompatibilityInfo);
+                    return new WindowManagerImpl(ctx.getOuterContext(),
+                            Display.DEFAULT_DISPLAY);
                 }});
 
         registerService(USER_SERVICE, new ServiceFetcher() {
@@ -525,7 +529,7 @@
 
     @Override
     public AssetManager getAssets() {
-        return mResources.getAssets();
+        return getResources().getAssets();
     }
 
     @Override
@@ -904,12 +908,13 @@
 
     /** @hide */
     @Override
-    public void startActivityAsUser(Intent intent, int userId) {
+    public void startActivityAsUser(Intent intent, UserHandle user) {
         try {
             ActivityManagerNative.getDefault().startActivityAsUser(
                 mMainThread.getApplicationThread(), intent,
                 intent.resolveTypeIfNeeded(getContentResolver()),
-                null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null, null, userId);
+                null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null, null,
+                user.getIdentifier());
         } catch (RemoteException re) {
         }
     }
@@ -929,12 +934,13 @@
 
     /** @hide */
     @Override
-    public void startActivityAsUser(Intent intent, Bundle options, int userId) {
+    public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
         try {
             ActivityManagerNative.getDefault().startActivityAsUser(
                 mMainThread.getApplicationThread(), intent,
                 intent.resolveTypeIfNeeded(getContentResolver()),
-                null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null, options, userId);
+                null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null, options,
+                user.getIdentifier());
         } catch (RemoteException re) {
         }
     }
@@ -1060,19 +1066,19 @@
     }
 
     @Override
-    public void sendBroadcastToUser(Intent intent, int userHandle) {
+    public void sendBroadcastAsUser(Intent intent, UserHandle user) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
             intent.setAllowFds(false);
             ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(),
                     intent, resolvedType, null, Activity.RESULT_OK, null, null, null, false, false,
-                    userHandle);
+                    user.getIdentifier());
         } catch (RemoteException e) {
         }
     }
 
     @Override
-    public void sendOrderedBroadcastToUser(Intent intent, int userHandle,
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
             BroadcastReceiver resultReceiver, Handler scheduler,
             int initialCode, String initialData, Bundle initialExtras) {
         IIntentReceiver rd = null;
@@ -1098,7 +1104,7 @@
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, null,
-                true, false, userHandle);
+                true, false, user.getIdentifier());
         } catch (RemoteException e) {
         }
     }
@@ -1257,7 +1263,7 @@
     @Override
     public boolean bindService(Intent service, ServiceConnection conn,
             int flags) {
-        return bindService(service, conn, flags, UserId.getUserId(Process.myUid()));
+        return bindService(service, conn, flags, UserHandle.getUserId(Process.myUid()));
     }
 
     /** @hide */
@@ -1591,10 +1597,25 @@
     }
 
     @Override
+    public Context createConfigurationContext(Configuration overrideConfiguration) {
+        ContextImpl c = new ContextImpl();
+        c.init(mPackageInfo, null, mMainThread);
+        c.mResources = mMainThread.getTopLevelResources(
+                mPackageInfo.getResDir(), overrideConfiguration,
+                mResources.getCompatibilityInfo());
+        return c;
+    }
+
+    @Override
     public boolean isRestricted() {
         return mRestricted;
     }
 
+    @Override
+    public CompatibilityInfoHolder getCompatibilityInfo() {
+        return mPackageInfo.mCompatibilityInfo;
+    }
+
     private File getDataDirFile() {
         if (mPackageInfo != null) {
             return mPackageInfo.getDataDirFile();
@@ -1659,12 +1680,11 @@
                         " compatiblity info:" + container.getDisplayMetrics());
             }
             mResources = mainThread.getTopLevelResources(
-                    mPackageInfo.getResDir(), container.getCompatibilityInfo());
+                    mPackageInfo.getResDir(), null, container.getCompatibilityInfo());
         }
         mMainThread = mainThread;
         mContentResolver = new ApplicationContentResolver(this, mainThread);
-
-        setActivityToken(activityToken);
+        mActivityToken = activityToken;
     }
 
     final void init(Resources resources, ActivityThread mainThread) {
@@ -1691,10 +1711,6 @@
         return mReceiverRestrictedContext = new ReceiverRestrictedContext(getOuterContext());
     }
 
-    final void setActivityToken(IBinder token) {
-        mActivityToken = token;
-    }
-
     final void setOuterContext(Context context) {
         mOuterContext = context;
     }
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index c9e092c..52a6557 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -20,6 +20,7 @@
 import android.animation.AnimatorInflater;
 import android.animation.AnimatorListenerAdapter;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.os.Bundle;
 import android.os.Handler;
@@ -427,6 +428,28 @@
         }
     };
 
+    private void throwException(RuntimeException ex) {
+        Log.e(TAG, ex.getMessage());
+        LogWriter logw = new LogWriter(Log.ERROR, TAG);
+        PrintWriter pw = new PrintWriter(logw);
+        if (mActivity != null) {
+            Log.e(TAG, "Activity state:");
+            try {
+                mActivity.dump("  ", null, pw, new String[] { });
+            } catch (Exception e) {
+                Log.e(TAG, "Failed dumping state", e);
+            }
+        } else {
+            Log.e(TAG, "Fragment manager state:");
+            try {
+                dump("  ", null, pw, new String[] { });
+            } catch (Exception e) {
+                Log.e(TAG, "Failed dumping state", e);
+            }
+        }
+        throw ex;
+    }
+
     @Override
     public FragmentTransaction beginTransaction() {
         return new BackStackRecord(this);
@@ -519,8 +542,8 @@
     @Override
     public void putFragment(Bundle bundle, String key, Fragment fragment) {
         if (fragment.mIndex < 0) {
-            throw new IllegalStateException("Fragment " + fragment
-                    + " is not currently in the FragmentManager");
+            throwException(new IllegalStateException("Fragment " + fragment
+                    + " is not currently in the FragmentManager"));
         }
         bundle.putInt(key, fragment.mIndex);
     }
@@ -532,13 +555,13 @@
             return null;
         }
         if (index >= mActive.size()) {
-            throw new IllegalStateException("Fragement no longer exists for key "
-                    + key + ": index " + index);
+            throwException(new IllegalStateException("Fragement no longer exists for key "
+                    + key + ": index " + index));
         }
         Fragment f = mActive.get(index);
         if (f == null) {
-            throw new IllegalStateException("Fragement no longer exists for key "
-                    + key + ": index " + index);
+            throwException(new IllegalStateException("Fragement no longer exists for key "
+                    + key + ": index " + index));
         }
         return f;
     }
@@ -546,8 +569,8 @@
     @Override
     public Fragment.SavedState saveFragmentInstanceState(Fragment fragment) {
         if (fragment.mIndex < 0) {
-            throw new IllegalStateException("Fragment " + fragment
-                    + " is not currently in the FragmentManager");
+            throwException(new IllegalStateException("Fragment " + fragment
+                    + " is not currently in the FragmentManager"));
         }
         if (fragment.mState > Fragment.INITIALIZING) {
             Bundle result = saveFragmentBasicState(fragment);
@@ -824,9 +847,11 @@
                             if (f.mContainerId != 0) {
                                 container = (ViewGroup)mActivity.findViewById(f.mContainerId);
                                 if (container == null && !f.mRestored) {
-                                    throw new IllegalArgumentException("No view found for id 0x"
-                                            + Integer.toHexString(f.mContainerId)
-                                            + " for fragment " + f);
+                                    throwException(new IllegalArgumentException(
+                                            "No view found for id 0x"
+                                            + Integer.toHexString(f.mContainerId) + " ("
+                                            + f.getResources().getResourceName(f.mContainerId)
+                                            + ") for fragment " + f));
                                 }
                             }
                             f.mContainer = container;
@@ -1587,12 +1612,9 @@
             Fragment f = mActive.get(i);
             if (f != null) {
                 if (f.mIndex < 0) {
-                    String msg = "Failure saving state: active " + f
-                            + " has cleared index: " + f.mIndex;
-                    Slog.e(TAG, msg);
-                    dump("  ", null, new PrintWriter(new LogWriter(
-                            Log.ERROR, TAG, Log.LOG_ID_SYSTEM)), new String[] { });
-                    throw new IllegalStateException(msg);
+                    throwException(new IllegalStateException(
+                            "Failure saving state: active " + f
+                            + " has cleared index: " + f.mIndex));
                 }
 
                 haveFragments = true;
@@ -1605,12 +1627,9 @@
 
                     if (f.mTarget != null) {
                         if (f.mTarget.mIndex < 0) {
-                            String msg = "Failure saving state: " + f
-                                + " has target not in fragment manager: " + f.mTarget;
-                            Slog.e(TAG, msg);
-                            dump("  ", null, new PrintWriter(new LogWriter(
-                                    Log.ERROR, TAG, Log.LOG_ID_SYSTEM)), new String[] { });
-                            throw new IllegalStateException(msg);
+                            throwException(new IllegalStateException(
+                                    "Failure saving state: " + f
+                                    + " has target not in fragment manager: " + f.mTarget));
                         }
                         if (fs.mSavedFragmentState == null) {
                             fs.mSavedFragmentState = new Bundle();
@@ -1649,12 +1668,9 @@
                 for (int i=0; i<N; i++) {
                     added[i] = mAdded.get(i).mIndex;
                     if (added[i] < 0) {
-                        String msg = "Failure saving state: active " + mAdded.get(i)
-                                + " has cleared index: " + added[i];
-                        Slog.e(TAG, msg);
-                        dump("  ", null, new PrintWriter(new LogWriter(
-                                Log.ERROR, TAG, Log.LOG_ID_SYSTEM)), new String[] { });
-                        throw new IllegalStateException(msg);
+                        throwException(new IllegalStateException(
+                                "Failure saving state: active " + mAdded.get(i)
+                                + " has cleared index: " + added[i]));
                     }
                     if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i
                             + ": " + mAdded.get(i));
@@ -1759,8 +1775,8 @@
             for (int i=0; i<fms.mAdded.length; i++) {
                 Fragment f = mActive.get(fms.mAdded[i]);
                 if (f == null) {
-                    throw new IllegalStateException(
-                            "No instantiated fragment for index #" + fms.mAdded[i]);
+                    throwException(new IllegalStateException(
+                            "No instantiated fragment for index #" + fms.mAdded[i]));
                 }
                 f.mAdded = true;
                 if (DEBUG) Log.v(TAG, "restoreAllState: making added #" + i + ": " + f);
@@ -1788,7 +1804,7 @@
     }
     
     public void attachActivity(Activity activity) {
-        if (mActivity != null) throw new IllegalStateException();
+        if (mActivity != null) throw new IllegalStateException("Already attached");
         mActivity = activity;
     }
     
diff --git a/core/java/android/app/ISearchManager.aidl b/core/java/android/app/ISearchManager.aidl
index 688cdfd..074d343 100644
--- a/core/java/android/app/ISearchManager.aidl
+++ b/core/java/android/app/ISearchManager.aidl
@@ -30,4 +30,5 @@
    List<ResolveInfo> getGlobalSearchActivities();
    ComponentName getGlobalSearchActivity();
    ComponentName getWebSearchActivity();
+   ComponentName getAssistIntent(int userHandle);
 }
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index ef61af7..22a21cd 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -16,13 +16,12 @@
 
 package android.app;
 
-import android.content.Context;
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.IBinder;
-import android.os.ServiceManager;
 import android.view.IWindowManager;
 import android.view.IOnKeyguardExitResult;
+import android.view.WindowManagerGlobal;
 
 /**
  * Class that can be used to lock and unlock the keyboard. Get an instance of this 
@@ -111,7 +110,7 @@
 
 
     KeyguardManager() {
-        mWM = IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
+        mWM = WindowManagerGlobal.getWindowManagerService();
     }
 
     /**
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index be4b284..1e89bb2 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -37,7 +37,7 @@
 import android.os.RemoteException;
 import android.os.StrictMode;
 import android.os.Trace;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.AndroidRuntimeException;
 import android.util.Slog;
 import android.view.CompatibilityInfoHolder;
@@ -120,8 +120,8 @@
         final int myUid = Process.myUid();
         mResDir = aInfo.uid == myUid ? aInfo.sourceDir
                 : aInfo.publicSourceDir;
-        if (!UserId.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
-            aInfo.dataDir = PackageManager.getDataDirForUser(UserId.getUserId(myUid),
+        if (!UserHandle.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
+            aInfo.dataDir = PackageManager.getDataDirForUser(UserHandle.getUserId(myUid),
                     mPackageName);
         }
         mSharedLibraries = aInfo.sharedLibraryFiles;
@@ -195,7 +195,7 @@
         ApplicationInfo ai = null;
         try {
             ai = ActivityThread.getPackageManager().getApplicationInfo(packageName,
-                    PackageManager.GET_SHARED_LIBRARY_FILES, UserId.myUserId());
+                    PackageManager.GET_SHARED_LIBRARY_FILES, UserHandle.myUserId());
         } catch (RemoteException e) {
             throw new AssertionError(e);
         }
@@ -358,7 +358,7 @@
         IPackageManager pm = ActivityThread.getPackageManager();
         android.content.pm.PackageInfo pi;
         try {
-            pi = pm.getPackageInfo(mPackageName, 0, UserId.myUserId());
+            pi = pm.getPackageInfo(mPackageName, 0, UserHandle.myUserId());
         } catch (RemoteException e) {
             throw new AssertionError(e);
         }
@@ -471,7 +471,7 @@
 
     public Resources getResources(ActivityThread mainThread) {
         if (mResources == null) {
-            mResources = mainThread.getTopLevelResources(mResDir, this);
+            mResources = mainThread.getTopLevelResources(mResDir, null, this);
         }
         return mResources;
     }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b2e69de..cb83dc2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -897,12 +897,16 @@
      * Builder class for {@link Notification} objects.
      * 
      * Provides a convenient way to set the various fields of a {@link Notification} and generate
-     * content views using the platform's notification layout template. 
+     * content views using the platform's notification layout template. If your app supports
+     * versions of Android as old as API level 4, you can instead use
+     * {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder},
+     * available in the <a href="{@docRoot}tools/extras/support-library.html">Android Support
+     * library</a>.
      * 
-     * Example:
+     * <p>Example:
      * 
      * <pre class="prettyprint">
-     * Notification noti = new Notification.Builder()
+     * Notification noti = new Notification.Builder(mContext)
      *         .setContentTitle(&quot;New mail from &quot; + sender.toString())
      *         .setContentText(subject)
      *         .setSmallIcon(R.drawable.new_mail)
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 8adc8a2..a57c516 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -27,6 +27,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.util.AndroidException;
 
 /**
@@ -617,6 +618,47 @@
     }
 
     /**
+     * Return the uid of the application that created this
+     * PendingIntent, that is the identity under which you will actually be
+     * sending the Intent.  The returned integer is supplied by the system, so
+     * that an application can not spoof its uid.
+     *
+     * @return The uid of the PendingIntent, or -1 if there is
+     * none associated with it.
+     */
+    public int getTargetUid() {
+        try {
+            return ActivityManagerNative.getDefault()
+                .getUidForIntentSender(mTarget);
+        } catch (RemoteException e) {
+            // Should never happen.
+            return -1;
+        }
+    }
+
+    /**
+     * Return the user handle of the application that created this
+     * PendingIntent, that is the user under which you will actually be
+     * sending the Intent.  The returned UserHandle is supplied by the system, so
+     * that an application can not spoof its user.  See
+     * {@link android.os.Process#myUserHandle() Process.myUserHandle()} for
+     * more explanation of user handles.
+     *
+     * @return The user handle of the PendingIntent, or null if there is
+     * none associated with it.
+     */
+    public UserHandle getTargetUserHandle() {
+        try {
+            int uid = ActivityManagerNative.getDefault()
+                .getUidForIntentSender(mTarget);
+            return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null;
+        } catch (RemoteException e) {
+            // Should never happen.
+            return null;
+        }
+    }
+
+    /**
      * @hide
      * Check to verify that this PendingIntent targets a specific package.
      */
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index d1d5131..43a163d 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -31,6 +31,7 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
@@ -845,14 +846,28 @@
      *
      * @hide
      */
-    public static final Intent getAssistIntent(Context context) {
-        PackageManager pm = context.getPackageManager();
-        Intent intent = new Intent(Intent.ACTION_ASSIST);
-        ComponentName component = intent.resolveActivity(pm);
-        if (component != null) {
-            intent.setComponent(component);
+    public Intent getAssistIntent(Context context) {
+        return getAssistIntent(context, UserHandle.myUserId());
+    }
+
+    /**
+     * Gets an intent for launching installed assistant activity, or null if not available.
+     * @return The assist intent.
+     *
+     * @hide
+     */
+    public Intent getAssistIntent(Context context, int userHandle) {
+        try {
+            ComponentName comp = mService.getAssistIntent(userHandle);
+            if (comp == null) {
+                return null;
+            }
+            Intent intent = new Intent(Intent.ACTION_ASSIST);
+            intent.setComponent(comp);
             return intent;
+        } catch (RemoteException re) {
+            Log.e(TAG, "getAssistIntent() failed: " + re);
+            return null;
         }
-        return null;
     }
 }
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index 615e8ce..201d7b2 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -17,7 +17,6 @@
 package android.app;
 
 import android.content.SharedPreferences;
-import android.os.FileUtils.FileStatus;
 import android.os.FileUtils;
 import android.os.Looper;
 import android.util.Log;
@@ -45,6 +44,11 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 
+import libcore.io.ErrnoException;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+import libcore.io.StructStat;
+
 final class SharedPreferencesImpl implements SharedPreferences {
     private static final String TAG = "SharedPreferencesImpl";
     private static final boolean DEBUG = false;
@@ -105,26 +109,32 @@
         }
 
         Map map = null;
-        FileStatus stat = new FileStatus();
-        if (FileUtils.getFileStatus(mFile.getPath(), stat) && mFile.canRead()) {
-            try {
-                BufferedInputStream str = new BufferedInputStream(
-                        new FileInputStream(mFile), 16*1024);
-                map = XmlUtils.readMapXml(str);
-                str.close();
-            } catch (XmlPullParserException e) {
-                Log.w(TAG, "getSharedPreferences", e);
-            } catch (FileNotFoundException e) {
-                Log.w(TAG, "getSharedPreferences", e);
-            } catch (IOException e) {
-                Log.w(TAG, "getSharedPreferences", e);
+        StructStat stat = null;
+        try {
+            stat = Libcore.os.stat(mFile.getPath());
+            if (mFile.canRead()) {
+                BufferedInputStream str = null;
+                try {
+                    str = new BufferedInputStream(
+                            new FileInputStream(mFile), 16*1024);
+                    map = XmlUtils.readMapXml(str);
+                } catch (XmlPullParserException e) {
+                    Log.w(TAG, "getSharedPreferences", e);
+                } catch (FileNotFoundException e) {
+                    Log.w(TAG, "getSharedPreferences", e);
+                } catch (IOException e) {
+                    Log.w(TAG, "getSharedPreferences", e);
+                } finally {
+                    IoUtils.closeQuietly(str);
+                }
             }
+        } catch (ErrnoException e) {
         }
         mLoaded = true;
         if (map != null) {
             mMap = map;
-            mStatTimestamp = stat.mtime;
-            mStatSize = stat.size;
+            mStatTimestamp = stat.st_mtime;
+            mStatSize = stat.st_size;
         } else {
             mMap = new HashMap<String, Object>();
         }
@@ -155,12 +165,21 @@
                 return false;
             }
         }
-        FileStatus stat = new FileStatus();
-        if (!FileUtils.getFileStatus(mFile.getPath(), stat)) {
+
+        final StructStat stat;
+        try {
+            /*
+             * Metadata operations don't usually count as a block guard
+             * violation, but we explicitly want this one.
+             */
+            BlockGuard.getThreadPolicy().onReadFromDisk();
+            stat = Libcore.os.stat(mFile.getPath());
+        } catch (ErrnoException e) {
             return true;
         }
+
         synchronized (this) {
-            return mStatTimestamp != stat.mtime || mStatSize != stat.size;
+            return mStatTimestamp != stat.st_mtime || mStatSize != stat.st_size;
         }
     }
 
@@ -577,12 +596,14 @@
             FileUtils.sync(str);
             str.close();
             ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
-            FileStatus stat = new FileStatus();
-            if (FileUtils.getFileStatus(mFile.getPath(), stat)) {
+            try {
+                final StructStat stat = Libcore.os.stat(mFile.getPath());
                 synchronized (this) {
-                    mStatTimestamp = stat.mtime;
-                    mStatSize = stat.size;
+                    mStatTimestamp = stat.st_mtime;
+                    mStatSize = stat.st_size;
                 }
+            } catch (ErrnoException e) {
+                // Do nothing
             }
             // Writing was successful, delete the backup file if there is one.
             mBackupFile.delete();
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 27843ac..1ad2e6d 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -43,6 +43,7 @@
 import android.util.Log;
 import android.view.ViewRootImpl;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -689,7 +690,7 @@
     public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
         try {
             //Log.v(TAG, "Sending new wallpaper offsets from app...");
-            ViewRootImpl.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+            WindowManagerGlobal.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
                     windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
             //Log.v(TAG, "...app returning after sending offsets!");
         } catch (RemoteException e) {
@@ -727,7 +728,7 @@
             int x, int y, int z, Bundle extras) {
         try {
             //Log.v(TAG, "Sending new wallpaper offsets from app...");
-            ViewRootImpl.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
+            WindowManagerGlobal.getWindowSession(mContext.getMainLooper()).sendWallpaperCommand(
                     windowToken, action, x, y, z, extras, false);
             //Log.v(TAG, "...app returning after sending offsets!");
         } catch (RemoteException e) {
@@ -747,7 +748,7 @@
      */
     public void clearWallpaperOffsets(IBinder windowToken) {
         try {
-            ViewRootImpl.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+            WindowManagerGlobal.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
                     windowToken, -1, -1, -1, -1);
         } catch (RemoteException e) {
             // Ignore.
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 2c19c0c..c76bf91 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -29,6 +29,7 @@
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
 import android.widget.RemoteViews;
+import android.widget.RemoteViews.OnClickHandler;
 
 import com.android.internal.appwidget.IAppWidgetHost;
 import com.android.internal.appwidget.IAppWidgetService;
@@ -83,7 +84,7 @@
         public UpdateHandler(Looper looper) {
             super(looper);
         }
-        
+
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case HANDLE_UPDATE: {
@@ -105,16 +106,25 @@
             }
         }
     }
-    
+
     Handler mHandler;
 
     int mHostId;
     Callbacks mCallbacks = new Callbacks();
     final HashMap<Integer,AppWidgetHostView> mViews = new HashMap<Integer, AppWidgetHostView>();
+    private OnClickHandler mOnClickHandler;
 
     public AppWidgetHost(Context context, int hostId) {
+        this(context, hostId, null);
+    }
+
+    /**
+     * @hide
+     */
+    public AppWidgetHost(Context context, int hostId, OnClickHandler handler) {
         mContext = context;
         mHostId = hostId;
+        mOnClickHandler = handler;
         mHandler = new UpdateHandler(context.getMainLooper());
         mDisplayMetrics = context.getResources().getDisplayMetrics();
         synchronized (sServiceLock) {
@@ -132,7 +142,7 @@
     public void startListening() {
         int[] updatedIds;
         ArrayList<RemoteViews> updatedViews = new ArrayList<RemoteViews>();
-        
+
         try {
             if (mPackageName == null) {
                 mPackageName = mContext.getPackageName();
@@ -180,7 +190,7 @@
     }
 
     /**
-     * Stop listening to changes for this AppWidget.  
+     * Stop listening to changes for this AppWidget.
      */
     public void deleteAppWidgetId(int appWidgetId) {
         synchronized (mViews) {
@@ -235,6 +245,7 @@
     public final AppWidgetHostView createView(Context context, int appWidgetId,
             AppWidgetProviderInfo appWidget) {
         AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);
+        view.setOnClickHandler(mOnClickHandler);
         view.setAppWidget(appWidgetId, appWidget);
         synchronized (mViews) {
             mViews.put(appWidgetId, view);
@@ -246,6 +257,7 @@
             throw new RuntimeException("system server dead?", e);
         }
         view.updateAppWidget(views);
+
         return view;
     }
 
@@ -255,7 +267,7 @@
      */
     protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
             AppWidgetProviderInfo appWidget) {
-        return new AppWidgetHostView(context);
+        return new AppWidgetHostView(context, mOnClickHandler);
     }
 
     /**
@@ -265,7 +277,7 @@
         AppWidgetHostView v;
 
         // Convert complex to dp -- we are getting the AppWidgetProviderInfo from the
-        // AppWidgetService, which doesn't have our context, hence we need to do the 
+        // AppWidgetService, which doesn't have our context, hence we need to do the
         // conversion here.
         appWidget.minWidth =
             TypedValue.complexToDimensionPixelSize(appWidget.minWidth, mDisplayMetrics);
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index ed95ae5..603ceb7 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -44,6 +44,7 @@
 import android.widget.BaseAdapter;
 import android.widget.FrameLayout;
 import android.widget.RemoteViews;
+import android.widget.RemoteViews.OnClickHandler;
 import android.widget.RemoteViewsAdapter.RemoteAdapterConnectionCallback;
 import android.widget.TextView;
 
@@ -83,7 +84,8 @@
     long mFadeStartTime = -1;
     Bitmap mOld;
     Paint mOldPaint = new Paint();
-    
+    private OnClickHandler mOnClickHandler;
+
     /**
      * Create a host view.  Uses default fade animations.
      */
@@ -92,9 +94,17 @@
     }
 
     /**
+     * @hide
+     */
+    public AppWidgetHostView(Context context, OnClickHandler handler) {
+        this(context, android.R.anim.fade_in, android.R.anim.fade_out);
+        mOnClickHandler = handler;
+    }
+
+    /**
      * Create a host view. Uses specified animations when pushing
      * {@link #updateAppWidget(RemoteViews)}.
-     * 
+     *
      * @param animationIn Resource ID of in animation to use
      * @param animationOut Resource ID of out animation to use
      */
@@ -109,6 +119,17 @@
     }
 
     /**
+     * Pass the given handler to RemoteViews when updating this widget. Unless this
+     * is done immediatly after construction, a call to {@link #updateAppWidget(RemoteViews)}
+     * should be made.
+     * @param handler
+     * @hide
+     */
+    public void setOnClickHandler(OnClickHandler handler) {
+        mOnClickHandler = handler;
+    }
+
+    /**
      * Set the AppWidget that will be displayed by this view. This method also adds default padding
      * to widgets, as described in {@link #getDefaultPaddingForWidget(Context, ComponentName, Rect)}
      * and can be overridden in order to add custom padding.
@@ -177,7 +198,7 @@
     public int getAppWidgetId() {
         return mAppWidgetId;
     }
-    
+
     public AppWidgetProviderInfo getAppWidgetInfo() {
         return mInfo;
     }
@@ -281,12 +302,13 @@
      * AppWidget provider. Will animate into these new views as needed
      */
     public void updateAppWidget(RemoteViews remoteViews) {
+
         if (LOGD) Log.d(TAG, "updateAppWidget called mOld=" + mOld);
 
         boolean recycled = false;
         View content = null;
         Exception exception = null;
-        
+
         // Capture the old view into a bitmap so we can do the crossfade.
         if (CROSSFADE) {
             if (mFadeStartTime < 0) {
@@ -305,7 +327,7 @@
                 }
             }
         }
-        
+
         if (remoteViews == null) {
             if (mViewMode == VIEW_MODE_DEFAULT) {
                 // We've already done this -- nothing to do.
@@ -324,7 +346,7 @@
             // layout matches, try recycling it
             if (content == null && layoutId == mLayoutId) {
                 try {
-                    remoteViews.reapply(mContext, mView);
+                    remoteViews.reapply(mContext, mView, mOnClickHandler);
                     content = mView;
                     recycled = true;
                     if (LOGD) Log.d(TAG, "was able to recycled existing layout");
@@ -332,11 +354,11 @@
                     exception = e;
                 }
             }
-            
+
             // Try normal RemoteView inflation
             if (content == null) {
                 try {
-                    content = remoteViews.apply(mContext, this);
+                    content = remoteViews.apply(mContext, this, mOnClickHandler);
                     if (LOGD) Log.d(TAG, "had to inflate new layout");
                 } catch (RuntimeException e) {
                     exception = e;
@@ -346,7 +368,7 @@
             mLayoutId = layoutId;
             mViewMode = VIEW_MODE_CONTENT;
         }
-        
+
         if (content == null) {
             if (mViewMode == VIEW_MODE_ERROR) {
                 // We've already done this -- nothing to do.
@@ -356,7 +378,7 @@
             content = getErrorView();
             mViewMode = VIEW_MODE_ERROR;
         }
-        
+
         if (!recycled) {
             prepareView(content);
             addView(content);
@@ -455,7 +477,7 @@
             return super.drawChild(canvas, child, drawingTime);
         }
     }
-    
+
     /**
      * Prepare the given view to be shown. This might include adjusting
      * {@link FrameLayout.LayoutParams} before inserting.
@@ -471,7 +493,7 @@
         requested.gravity = Gravity.CENTER;
         view.setLayoutParams(requested);
     }
-    
+
     /**
      * Inflate and return the default layout requested by AppWidget provider.
      */
@@ -481,7 +503,7 @@
         }
         View defaultView = null;
         Exception exception = null;
-        
+
         try {
             if (mInfo != null) {
                 Context theirContext = mContext.createPackageContext(
@@ -500,19 +522,19 @@
         } catch (RuntimeException e) {
             exception = e;
         }
-        
+
         if (exception != null) {
             Log.w(TAG, "Error inflating AppWidget " + mInfo + ": " + exception.toString());
         }
-        
+
         if (defaultView == null) {
             if (LOGD) Log.d(TAG, "getDefaultView couldn't find any view, so inflating error");
             defaultView = getErrorView();
         }
-        
+
         return defaultView;
     }
-    
+
     /**
      * Inflate and return a view that represents an error state.
      */
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index ceaf17e..17d404d 100755
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -504,7 +504,10 @@
      *         immediate error
      */
     public boolean enable() {
-        boolean enabled = false;
+        if (isEnabled() == true){
+            if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
+            return true;
+        }
         try {
             return mManagerService.enable();
         } catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -1246,8 +1249,14 @@
      * @hide
      */
     public boolean enableNoAutoConnect() {
-        // TODO avoid auto-connect in the new stack.
-        return enable();
+        if (isEnabled() == true){
+            if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT is already enabled..!");
+            return true;
+        }
+        try {
+            return mManagerService.enableNoAutoConnect();
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
     }
 
     /**
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
old mode 100644
new mode 100755
index f82da82..de8fe91
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -21,6 +21,7 @@
     void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
     boolean isEnabled();
     boolean enable();
+    boolean enableNoAutoConnect();
     boolean disable(boolean persist);
 
     String getAddress();
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index b22179e..23d8f46 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -35,7 +35,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.Log;
 
 import java.io.File;
@@ -279,7 +279,7 @@
             final int uid = Binder.getCallingUid();
             String missingPerm = null;
 
-            if (uid == mMyUid) {
+            if (UserHandle.isSameApp(uid, mMyUid)) {
                 return;
             }
 
@@ -340,7 +340,7 @@
             final int uid = Binder.getCallingUid();
             String missingPerm = null;
 
-            if (uid == mMyUid) {
+            if (UserHandle.isSameApp(uid, mMyUid)) {
                 return;
             }
 
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index 1a07504..472fe94 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -26,7 +26,7 @@
 import android.os.Parcel;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseIntArray;
 import android.Manifest;
@@ -168,7 +168,7 @@
                     + ", syncToNetwork " + syncToNetwork);
         }
 
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
         // This makes it so that future permission checks will be in the context of this
         // process rather than the caller's process. We will restore this before returning.
         long identityToken = clearCallingIdentity();
@@ -236,7 +236,7 @@
 
     public void requestSync(Account account, String authority, Bundle extras) {
         ContentResolver.validateSyncExtrasBundle(extras);
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         // This makes it so that future permission checks will be in the context of this
         // process rather than the caller's process. We will restore this before returning.
@@ -259,7 +259,7 @@
      * @param authority filter the pending and active syncs to cancel using this authority
      */
     public void cancelSync(Account account, String authority) {
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         // This makes it so that future permission checks will be in the context of this
         // process rather than the caller's process. We will restore this before returning.
@@ -294,7 +294,7 @@
     public boolean getSyncAutomatically(Account account, String providerName) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
                 "no permission to read the sync settings");
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         long identityToken = clearCallingIdentity();
         try {
@@ -312,7 +312,7 @@
     public void setSyncAutomatically(Account account, String providerName, boolean sync) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                 "no permission to write the sync settings");
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         long identityToken = clearCallingIdentity();
         try {
@@ -330,7 +330,7 @@
             long pollFrequency) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                 "no permission to write the sync settings");
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         long identityToken = clearCallingIdentity();
         try {
@@ -344,7 +344,7 @@
     public void removePeriodicSync(Account account, String authority, Bundle extras) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                 "no permission to write the sync settings");
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         long identityToken = clearCallingIdentity();
         try {
@@ -358,7 +358,7 @@
     public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
                 "no permission to read the sync settings");
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         long identityToken = clearCallingIdentity();
         try {
@@ -372,7 +372,7 @@
     public int getIsSyncable(Account account, String providerName) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
                 "no permission to read the sync settings");
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         long identityToken = clearCallingIdentity();
         try {
@@ -390,7 +390,7 @@
     public void setIsSyncable(Account account, String providerName, int syncable) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                 "no permission to write the sync settings");
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         long identityToken = clearCallingIdentity();
         try {
@@ -407,7 +407,7 @@
     public boolean getMasterSyncAutomatically() {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
                 "no permission to read the sync settings");
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         long identityToken = clearCallingIdentity();
         try {
@@ -424,7 +424,7 @@
     public void setMasterSyncAutomatically(boolean flag) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                 "no permission to write the sync settings");
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         long identityToken = clearCallingIdentity();
         try {
@@ -440,7 +440,7 @@
     public boolean isSyncActive(Account account, String authority) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
                 "no permission to read the sync stats");
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         long identityToken = clearCallingIdentity();
         try {
@@ -458,7 +458,7 @@
     public List<SyncInfo> getCurrentSyncs() {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
                 "no permission to read the sync stats");
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         long identityToken = clearCallingIdentity();
         try {
@@ -471,7 +471,7 @@
     public SyncStatusInfo getSyncStatus(Account account, String authority) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
                 "no permission to read the sync stats");
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         long identityToken = clearCallingIdentity();
         try {
@@ -489,7 +489,7 @@
     public boolean isSyncPending(Account account, String authority) {
         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
                 "no permission to read the sync stats");
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         long identityToken = clearCallingIdentity();
         try {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index bf60a96..1460bf5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -19,6 +19,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.database.DatabaseErrorHandler;
@@ -31,7 +32,9 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.UserHandle;
 import android.util.AttributeSet;
+import android.view.CompatibilityInfoHolder;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -854,11 +857,11 @@
      * Same as {@link #startActivity(Intent)}, but for a specific user. It requires holding
      * the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission.
      * @param intent The description of the activity to start.
-     * @param userId The user id of the user to start this activity for.
+     * @param user The UserHandle of the user to start this activity for.
      * @throws ActivityNotFoundException
      * @hide
      */
-    public void startActivityAsUser(Intent intent, int userId) {
+    public void startActivityAsUser(Intent intent, UserHandle user) {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 
@@ -897,11 +900,11 @@
      * May be null if there are no options.  See {@link android.app.ActivityOptions}
      * for how to build the Bundle supplied here; there are no supported definitions
      * for building it manually.
-     * @param userId The user id of the user to start this activity for.
+     * @param user The UserHandle of the user to start this activity for.
      * @throws ActivityNotFoundException
      * @hide
      */
-    public void startActivityAsUser(Intent intent, Bundle options, int userId) {
+    public void startActivityAsUser(Intent intent, Bundle options, UserHandle userId) {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 
@@ -1118,10 +1121,10 @@
      * requires holding the {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
      * permission.
      * @param intent The intent to broadcast
-     * @param userHandle User to send the intent to.
+     * @param user UserHandle to send the intent to.
      * @see #sendBroadcast(Intent)
      */
-    public abstract void sendBroadcastToUser(Intent intent, int userHandle);
+    public abstract void sendBroadcastAsUser(Intent intent, UserHandle user);
 
     /**
      * Same as
@@ -1135,7 +1138,7 @@
      *
      * @param intent The Intent to broadcast; all receivers matching this
      *               Intent will receive the broadcast.
-     * @param userHandle User to send the intent to.
+     * @param user UserHandle to send the intent to.
      * @param resultReceiver Your own BroadcastReceiver to treat as the final
      *                       receiver of the broadcast.
      * @param scheduler A custom Handler with which to schedule the
@@ -1150,7 +1153,7 @@
      *
      * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
      */
-    public abstract void sendOrderedBroadcastToUser(Intent intent, int userHandle,
+    public abstract void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
             BroadcastReceiver resultReceiver, Handler scheduler,
             int initialCode, String initialData, Bundle initialExtras);
 
@@ -2445,6 +2448,33 @@
             int flags) throws PackageManager.NameNotFoundException;
 
     /**
+     * Return a new Context object for the current Context but whose resources
+     * are adjusted to match the given Configuration.  Each call to this method
+     * returns a new instance of a Contex object; Context objects are not
+     * shared, however common state (ClassLoader, other Resources for the
+     * same configuration) may be so the Context itself can be fairly lightweight.
+     *
+     * @param overrideConfiguration A {@link Configuration} specifying what
+     * values to modify in the base Configuration of the original Context's
+     * resources.  If the base configuration changes (such as due to an
+     * orientation change), the resources of this context will also change except
+     * for those that have been explicitly overridden with a value here.
+     *
+     * @return A Context for the application.
+     */
+    public abstract Context createConfigurationContext(Configuration overrideConfiguration);
+
+    /**
+     * Gets the compatibility info holder for this context.  This information
+     * is provided on a per-application basis and is used to simulate lower density
+     * display metrics for legacy applications.
+     *
+     * @return The compatibility info holder, or null if not required by the application.
+     * @hide
+     */
+    public abstract CompatibilityInfoHolder getCompatibilityInfo();
+
+    /**
      * Indicates whether this Context is restricted.
      *
      * @return True if this Context is restricted, false otherwise.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index ff4c9a1..3a13725 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -19,6 +19,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
@@ -29,6 +30,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.UserHandle;
+import android.view.CompatibilityInfoHolder;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -278,8 +281,8 @@
 
     /** @hide */
     @Override
-    public void startActivityAsUser(Intent intent, int userId) {
-        mBase.startActivityAsUser(intent, userId);
+    public void startActivityAsUser(Intent intent, UserHandle user) {
+        mBase.startActivityAsUser(intent, user);
     }
 
     @Override
@@ -289,8 +292,8 @@
 
     /** @hide */
     @Override
-    public void startActivityAsUser(Intent intent, Bundle options, int userId) {
-        mBase.startActivityAsUser(intent, options, userId);
+    public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
+        mBase.startActivityAsUser(intent, options, user);
     }
 
     @Override
@@ -346,15 +349,15 @@
     }
 
     @Override
-    public void sendBroadcastToUser(Intent intent, int userHandle) {
-        mBase.sendBroadcastToUser(intent, userHandle);
+    public void sendBroadcastAsUser(Intent intent, UserHandle user) {
+        mBase.sendBroadcastAsUser(intent, user);
     }
 
     @Override
-    public void sendOrderedBroadcastToUser(Intent intent, int userHandle,
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
             BroadcastReceiver resultReceiver, Handler scheduler,
             int initialCode, String initialData, Bundle initialExtras) {
-        mBase.sendOrderedBroadcastToUser(intent, userHandle, resultReceiver,
+        mBase.sendOrderedBroadcastAsUser(intent, user, resultReceiver,
                 scheduler, initialCode, initialData, initialExtras);
     }
 
@@ -533,7 +536,18 @@
     }
 
     @Override
+    public Context createConfigurationContext(Configuration overrideConfiguration) {
+        return mBase.createConfigurationContext(overrideConfiguration);
+    }
+
+    @Override
     public boolean isRestricted() {
         return mBase.isRestricted();
     }
+
+    /** @hide */
+    @Override
+    public CompatibilityInfoHolder getCompatibilityInfo() {
+        return mBase.getCompatibilityInfo();
+    }
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d325186..06edf32 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -571,7 +571,7 @@
  *     <li> {@link #EXTRA_INITIAL_INTENTS}
  *     <li> {@link #EXTRA_INTENT}
  *     <li> {@link #EXTRA_KEY_EVENT}
- *     <li> {@link #EXTRA_ORIGINATING_URL}
+ *     <li> {@link #EXTRA_ORIGINATING_URI}
  *     <li> {@link #EXTRA_PHONE_NUMBER}
  *     <li> {@link #EXTRA_REFERRER}
  *     <li> {@link #EXTRA_REMOTE_INTENT_TOKEN}
@@ -1288,17 +1288,17 @@
             = "android.intent.extra.NOT_UNKNOWN_SOURCE";
 
     /**
-     * Used as a string extra field with {@link #ACTION_INSTALL_PACKAGE} and
-     * {@link #ACTION_VIEW} to indicate the URL from which the local APK in the Intent
+     * Used as a URI extra field with {@link #ACTION_INSTALL_PACKAGE} and
+     * {@link #ACTION_VIEW} to indicate the URI from which the local APK in the Intent
      * data field originated from.
      */
-    public static final String EXTRA_ORIGINATING_URL
-            = "android.intent.extra.ORIGINATING_URL";
+    public static final String EXTRA_ORIGINATING_URI
+            = "android.intent.extra.ORIGINATING_URI";
 
     /**
-     * Used as a string extra field with {@link #ACTION_INSTALL_PACKAGE} and
-     * {@link #ACTION_VIEW} to indicate the HTTP referrer associated with the Intent
-     * data field or {@link #EXTRA_ORIGINATING_URL}.
+     * Used as a URI extra field with {@link #ACTION_INSTALL_PACKAGE} and
+     * {@link #ACTION_VIEW} to indicate the HTTP referrer URI associated with the Intent
+     * data field or {@link #EXTRA_ORIGINATING_URI}.
      */
     public static final String EXTRA_REFERRER
             = "android.intent.extra.REFERRER";
@@ -2279,24 +2279,24 @@
             "android.intent.action.PRE_BOOT_COMPLETED";
 
     /**
-     * Broadcast sent to the system when a user is added. Carries an extra EXTRA_USERID that has the
-     * userid of the new user.
+     * Broadcast sent to the system when a user is added. Carries an extra EXTRA_USER_HANDLE that has the
+     * userHandle of the new user.
      * @hide
      */
     public static final String ACTION_USER_ADDED =
             "android.intent.action.USER_ADDED";
 
     /**
-     * Broadcast sent to the system when a user is removed. Carries an extra EXTRA_USERID that has
-     * the userid of the user.
+     * Broadcast sent to the system when a user is removed. Carries an extra EXTRA_USER_HANDLE that has
+     * the userHandle of the user.
      * @hide
      */
     public static final String ACTION_USER_REMOVED =
             "android.intent.action.USER_REMOVED";
 
     /**
-     * Broadcast sent to the system when the user switches. Carries an extra EXTRA_USERID that has
-     * the userid of the user to become the current one.
+     * Broadcast sent to the system when the user switches. Carries an extra EXTRA_USER_HANDLE that has
+     * the userHandle of the user to become the current one.
      * @hide
      */
     public static final String ACTION_USER_SWITCHED =
@@ -2852,12 +2852,12 @@
         "android.intent.extra.LOCAL_ONLY";
 
     /**
-     * The userid 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
      */
-    public static final String EXTRA_USERID =
-            "android.intent.extra.user_id";
+    public static final String EXTRA_USER_HANDLE =
+            "android.intent.extra.user_handle";
 
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index 4db4bdc..079241a 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -27,6 +27,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.util.AndroidException;
 
 
@@ -223,6 +224,47 @@
     }
 
     /**
+     * Return the uid of the application that created this
+     * PendingIntent, that is the identity under which you will actually be
+     * sending the Intent.  The returned integer is supplied by the system, so
+     * that an application can not spoof its uid.
+     *
+     * @return The uid of the PendingIntent, or -1 if there is
+     * none associated with it.
+     */
+    public int getTargetUid() {
+        try {
+            return ActivityManagerNative.getDefault()
+                .getUidForIntentSender(mTarget);
+        } catch (RemoteException e) {
+            // Should never happen.
+            return -1;
+        }
+    }
+
+    /**
+     * Return the user handle of the application that created this
+     * PendingIntent, that is the user under which you will actually be
+     * sending the Intent.  The returned UserHandle is supplied by the system, so
+     * that an application can not spoof its user.  See
+     * {@link android.os.Process#myUserHandle() Process.myUserHandle()} for
+     * more explanation of user handles.
+     *
+     * @return The user handle of the PendingIntent, or null if there is
+     * none associated with it.
+     */
+    public UserHandle getTargetUserHandle() {
+        try {
+            int uid = ActivityManagerNative.getDefault()
+                .getUidForIntentSender(mTarget);
+            return uid > 0 ? new UserHandle(UserHandle.getUserId(uid)) : null;
+        } catch (RemoteException e) {
+            // Should never happen.
+            return null;
+        }
+    }
+
+    /**
      * Comparison operator on two IntentSender objects, such that true
      * is returned then they both represent the same operation from the
      * same package.
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index e6303b9..ee075b4 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -52,7 +52,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.WorkSource;
 import android.provider.Settings;
@@ -174,7 +174,7 @@
                             Log.v(TAG, "Internal storage is low.");
                         }
                         mStorageIsLow = true;
-                        cancelActiveSync(null /* any account */, UserId.USER_ALL,
+                        cancelActiveSync(null /* any account */, UserHandle.USER_ALL,
                                 null /* any authority */);
                     } else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
                         if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -195,7 +195,7 @@
     private BroadcastReceiver mBackgroundDataSettingChanged = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
             if (getConnectivityManager().getBackgroundDataSetting()) {
-                scheduleSync(null /* account */, UserId.USER_ALL, null /* authority */,
+                scheduleSync(null /* account */, UserHandle.USER_ALL, null /* authority */,
                         new Bundle(), 0 /* delay */,
                         false /* onlyThoseWithUnknownSyncableState */);
             }
@@ -287,7 +287,7 @@
             // a chance to set their syncable state.
 
             boolean onlyThoseWithUnkownSyncableState = justBootedUp;
-            scheduleSync(null, UserId.USER_ALL, null, null, 0 /* no delay */,
+            scheduleSync(null, UserHandle.USER_ALL, null, null, 0 /* no delay */,
                     onlyThoseWithUnkownSyncableState);
         }
     }
@@ -371,7 +371,7 @@
         mSyncAdapters.setListener(new RegisteredServicesCacheListener<SyncAdapterType>() {
             public void onServiceChanged(SyncAdapterType type, boolean removed) {
                 if (!removed) {
-                    scheduleSync(null, UserId.USER_ALL, type.authority, null, 0 /* no delay */,
+                    scheduleSync(null, UserHandle.USER_ALL, type.authority, null, 0 /* no delay */,
                             false /* onlyThoseWithUnkownSyncableState */);
                 }
             }
@@ -517,7 +517,7 @@
         }
 
         AccountAndUser[] accounts;
-        if (requestedAccount != null && userId != UserId.USER_ALL) {
+        if (requestedAccount != null && userId != UserHandle.USER_ALL) {
             accounts = new AccountAndUser[] { new AccountAndUser(requestedAccount, userId) };
         } else {
             // if the accounts aren't configured yet then we can't support an account-less
@@ -895,7 +895,7 @@
     }
 
     private void onUserRemoved(Intent intent) {
-        int userId = intent.getIntExtra(Intent.EXTRA_USERID, -1);
+        int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
         if (userId == -1) return;
 
         // Clean up the storage engine database
@@ -2180,7 +2180,7 @@
                         }
                     }
                     // check if the userid matches
-                    if (userId != UserId.USER_ALL
+                    if (userId != UserHandle.USER_ALL
                             && userId != activeSyncContext.mSyncOperation.userId) {
                         continue;
                     }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 22807a4..3f4b994 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -39,6 +39,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
+import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
@@ -200,7 +201,7 @@
     List<PackageInfo> getPreferredPackages(int flags);
 
     void addPreferredActivity(in IntentFilter filter, int match,
-            in ComponentName[] set, in ComponentName activity);
+            in ComponentName[] set, in ComponentName activity, int userId);
 
     void replacePreferredActivity(in IntentFilter filter, int match,
             in ComponentName[] set, in ComponentName activity);
@@ -304,10 +305,11 @@
      * Get package statistics including the code, data and cache size for
      * an already installed package
      * @param packageName The package name of the application
+     * @param userHandle Which user the size should be retrieved for
      * @param observer a callback to use to notify when the asynchronous
      * retrieval of information is complete.
      */
-    void getPackageSizeInfo(in String packageName, IPackageStatsObserver observer);
+    void getPackageSizeInfo(in String packageName, int userHandle, IPackageStatsObserver observer);
     
     /**
      * Get a list of shared libraries that are available on the
@@ -362,6 +364,11 @@
             int flags, in String installerPackageName, in Uri verificationURI,
             in ManifestDigest manifestDigest, in ContainerEncryptionParams encryptionParams);
 
+    void installPackageWithVerificationAndEncryption(in Uri packageURI,
+            in IPackageInstallObserver observer, int flags, in String installerPackageName,
+            in VerificationParams verificationParams,
+            in ContainerEncryptionParams encryptionParams);
+
     void verifyPendingInstall(int id, int verificationCode);
 
     VerifierDeviceIdentity getVerifierDeviceIdentity();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f287ca5..0461dd1 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -28,6 +28,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Environment;
+import android.os.UserHandle;
 import android.util.AndroidException;
 import android.util.DisplayMetrics;
 
@@ -2227,6 +2228,37 @@
             ContainerEncryptionParams encryptionParams);
 
     /**
+     * Similar to
+     * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but
+     * with an extra verification information provided.
+     *
+     * @param packageURI The location of the package file to install. This can
+     *            be a 'file:' or a 'content:' URI.
+     * @param observer An observer callback to get notified when the package
+     *            installation is complete.
+     *            {@link IPackageInstallObserver#packageInstalled(String, int)}
+     *            will be called when that happens. observer may be null to
+     *            indicate that no callback is desired.
+     * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
+     *            {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}
+     *            .
+     * @param installerPackageName Optional package name of the application that
+     *            is performing the installation. This identifies which market
+     *            the package came from.
+     * @param verificationParams an object that holds signal information to
+     *            assist verification. May be {@code null}.
+     * @param encryptionParams if the package to be installed is encrypted,
+     *            these parameters describing the encryption and authentication
+     *            used. May be {@code null}.
+     *
+     * @hide
+     */
+    public abstract void installPackageWithVerificationAndEncryption(Uri packageURI,
+            IPackageInstallObserver observer, int flags, String installerPackageName,
+            VerificationParams verificationParams,
+            ContainerEncryptionParams encryptionParams);
+
+    /**
      * Allows a package listening to the
      * {@link Intent#ACTION_PACKAGE_NEEDS_VERIFICATION package verification
      * broadcast} to respond to the package manager. The response must include
@@ -2376,6 +2408,7 @@
      * should have the {@link android.Manifest.permission#GET_PACKAGE_SIZE} permission.
      *
      * @param packageName The name of the package whose size information is to be retrieved
+     * @param userHandle The user whose size information should be retrieved.
      * @param observer An observer callback to get notified when the operation
      * is complete.
      * {@link android.content.pm.IPackageStatsObserver#onGetStatsCompleted(PackageStats, boolean)}
@@ -2386,10 +2419,20 @@
      *
      * @hide
      */
-    public abstract void getPackageSizeInfo(String packageName,
+    public abstract void getPackageSizeInfo(String packageName, int userHandle,
             IPackageStatsObserver observer);
 
     /**
+     * Like {@link #getPackageSizeInfo(String, int, IPackageStatsObserver)}, but
+     * returns the size for the calling user.
+     *
+     * @hide
+     */
+    public void getPackageSizeInfo(String packageName, IPackageStatsObserver observer) {
+        getPackageSizeInfo(packageName, UserHandle.myUserId(), observer);
+    }
+
+    /**
      * @deprecated This function no longer does anything; it was an old
      * approach to managing preferred activities, which has been superceeded
      * (and conflicts with) the modern activity-based preferences.
@@ -2460,6 +2503,17 @@
             ComponentName[] set, ComponentName activity);
 
     /**
+     * Same as {@link #addPreferredActivity(IntentFilter, int,
+            ComponentName[], ComponentName)}, but with a specific userId to apply the preference
+            to.
+     * @hide
+     */
+    public void addPreferredActivity(IntentFilter filter, int match,
+            ComponentName[] set, ComponentName activity, int userId) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * @deprecated This is a protected API that should not have been available
      * to third party applications.  It is the platform's responsibility for
      * assigning preferred activities and this can not be directly modified.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index d906401..ac75040 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -28,7 +28,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.PatternMatcher;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.util.Base64;
 import android.util.DisplayMetrics;
@@ -249,7 +249,7 @@
 
         return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
                 grantedPermissions, false, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
-                UserId.getCallingUserId());
+                UserHandle.getCallingUserId());
     }
 
     /**
@@ -263,7 +263,7 @@
             HashSet<String> grantedPermissions, boolean stopped, int enabledState) {
 
         return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime,
-                grantedPermissions, stopped, enabledState, UserId.getCallingUserId());
+                grantedPermissions, stopped, enabledState, UserHandle.getCallingUserId());
     }
 
     public static PackageInfo generatePackageInfo(PackageParser.Package p,
@@ -3478,7 +3478,7 @@
 
     public static ApplicationInfo generateApplicationInfo(Package p, int flags, boolean stopped,
             int enabledState) {
-        return generateApplicationInfo(p, flags, stopped, enabledState, UserId.getCallingUserId());
+        return generateApplicationInfo(p, flags, stopped, enabledState, UserHandle.getCallingUserId());
     }
 
     public static ApplicationInfo generateApplicationInfo(Package p, int flags,
@@ -3508,7 +3508,7 @@
         // Make shallow copy so we can store the metadata/libraries safely
         ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
         if (userId != 0) {
-            ai.uid = UserId.getUid(userId, ai.uid);
+            ai.uid = UserHandle.getUid(userId, ai.uid);
             ai.dataDir = PackageManager.getDataDirForUser(userId, ai.packageName);
         }
         if ((flags & PackageManager.GET_META_DATA) != 0) {
@@ -3616,7 +3616,7 @@
             int enabledState, int userId) {
         if (s == null) return null;
         if (!copyNeeded(flags, s.owner, enabledState, s.metaData)
-                && userId == UserId.getUserId(s.info.applicationInfo.uid)) {
+                && userId == UserHandle.getUserId(s.info.applicationInfo.uid)) {
             return s.info;
         }
         // Make shallow copies so we can store the metadata safely
diff --git a/core/java/android/content/pm/PackageStats.java b/core/java/android/content/pm/PackageStats.java
index 1205da7..cb9039b 100644
--- a/core/java/android/content/pm/PackageStats.java
+++ b/core/java/android/content/pm/PackageStats.java
@@ -18,6 +18,7 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 
 /**
  * implementation of PackageStats associated with a
@@ -27,6 +28,9 @@
     /** Name of the package to which this stats applies. */
     public String packageName;
 
+    /** @hide */
+    public int userHandle;
+
     /** Size of the code (e.g., APK) */
     public long codeSize;
 
@@ -78,33 +82,58 @@
     public String toString() {
         final StringBuilder sb = new StringBuilder("PackageStats{");
         sb.append(Integer.toHexString(System.identityHashCode(this)));
-        sb.append(" packageName=");
+        sb.append(" ");
         sb.append(packageName);
-        sb.append(",codeSize=");
-        sb.append(codeSize);
-        sb.append(",dataSize=");
-        sb.append(dataSize);
-        sb.append(",cacheSize=");
-        sb.append(cacheSize);
-        sb.append(",externalCodeSize=");
-        sb.append(externalCodeSize);
-        sb.append(",externalDataSize=");
-        sb.append(externalDataSize);
-        sb.append(",externalCacheSize=");
-        sb.append(externalCacheSize);
-        sb.append(",externalMediaSize=");
-        sb.append(externalMediaSize);
-        sb.append(",externalObbSize=");
-        sb.append(externalObbSize);
+        if (codeSize != 0) {
+            sb.append(" code=");
+            sb.append(codeSize);
+        }
+        if (dataSize != 0) {
+            sb.append(" data=");
+            sb.append(dataSize);
+        }
+        if (cacheSize != 0) {
+            sb.append(" cache=");
+            sb.append(cacheSize);
+        }
+        if (externalCodeSize != 0) {
+            sb.append(" extCode=");
+            sb.append(externalCodeSize);
+        }
+        if (externalDataSize != 0) {
+            sb.append(" extData=");
+            sb.append(externalDataSize);
+        }
+        if (externalCacheSize != 0) {
+            sb.append(" extCache=");
+            sb.append(externalCacheSize);
+        }
+        if (externalMediaSize != 0) {
+            sb.append(" media=");
+            sb.append(externalMediaSize);
+        }
+        if (externalObbSize != 0) {
+            sb.append(" obb=");
+            sb.append(externalObbSize);
+        }
+        sb.append("}");
         return sb.toString();
     }
 
     public PackageStats(String pkgName) {
         packageName = pkgName;
+        userHandle = UserHandle.myUserId();
+    }
+
+    /** @hide */
+    public PackageStats(String pkgName, int userHandle) {
+        this.packageName = pkgName;
+        this.userHandle = userHandle;
     }
 
     public PackageStats(Parcel source) {
         packageName = source.readString();
+        userHandle = source.readInt();
         codeSize = source.readLong();
         dataSize = source.readLong();
         cacheSize = source.readLong();
@@ -117,6 +146,7 @@
 
     public PackageStats(PackageStats pStats) {
         packageName = pStats.packageName;
+        userHandle = pStats.userHandle;
         codeSize = pStats.codeSize;
         dataSize = pStats.dataSize;
         cacheSize = pStats.cacheSize;
@@ -133,6 +163,7 @@
 
     public void writeToParcel(Parcel dest, int parcelableFlags){
         dest.writeString(packageName);
+        dest.writeInt(userHandle);
         dest.writeLong(codeSize);
         dest.writeLong(dataSize);
         dest.writeLong(cacheSize);
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 638e273..060a235 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -53,6 +53,7 @@
     public static final int FLAG_RESTRICTED = 0x00000008;
 
     public int id;
+    public int serialNumber;
     public String name;
     public String iconPath;
     public int flags;
@@ -88,6 +89,7 @@
         iconPath = orig.iconPath;
         id = orig.id;
         flags = orig.flags;
+        serialNumber = orig.serialNumber;
     }
 
     @Override
@@ -104,6 +106,7 @@
         dest.writeString(name);
         dest.writeString(iconPath);
         dest.writeInt(flags);
+        dest.writeInt(serialNumber);
     }
 
     public static final Parcelable.Creator<UserInfo> CREATOR
@@ -121,5 +124,6 @@
         name = source.readString();
         iconPath = source.readString();
         flags = source.readInt();
+        serialNumber = source.readInt();
     }
 }
diff --git a/core/java/android/content/pm/VerificationParams.aidl b/core/java/android/content/pm/VerificationParams.aidl
new file mode 100644
index 0000000..5bb7f6962
--- /dev/null
+++ b/core/java/android/content/pm/VerificationParams.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+parcelable VerificationParams;
diff --git a/core/java/android/content/pm/VerificationParams.java b/core/java/android/content/pm/VerificationParams.java
new file mode 100644
index 0000000..9bec87e
--- /dev/null
+++ b/core/java/android/content/pm/VerificationParams.java
@@ -0,0 +1,187 @@
+/*
+ * 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.content.pm;
+
+import android.content.pm.ManifestDigest;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents verification parameters used to verify packages to be installed.
+ *
+ * @hide
+ */
+public class VerificationParams implements Parcelable {
+    /** What we print out first when toString() is called. */
+    private static final String TO_STRING_PREFIX = "VerificationParams{";
+
+    /** The location of the supplementary verification file. */
+    private final Uri mVerificationURI;
+
+    /** URI referencing where the package was downloaded from. */
+    private final Uri mOriginatingURI;
+
+    /** HTTP referrer URI associated with the originatingURI. */
+    private final Uri mReferrer;
+
+    /**
+     * An object that holds the digest of the package which can be used to
+     * verify ownership.
+     */
+    private final ManifestDigest mManifestDigest;
+
+    /**
+     * Creates verification specifications for installing with application verification.
+     *
+     * @param verificationURI The location of the supplementary verification
+     *            file. This can be a 'file:' or a 'content:' URI. May be {@code null}.
+     * @param originatingURI URI referencing where the package was downloaded
+     *            from. May be {@code null}.
+     * @param referrer HTTP referrer URI associated with the originatingURI.
+     *            May be {@code null}.
+     * @param manifestDigest an object that holds the digest of the package
+     *            which can be used to verify ownership. May be {@code null}.
+     */
+    public VerificationParams(Uri verificationURI, Uri originatingURI, Uri referrer,
+            ManifestDigest manifestDigest) {
+        mVerificationURI = verificationURI;
+        mOriginatingURI = originatingURI;
+        mReferrer = referrer;
+        mManifestDigest = manifestDigest;
+    }
+
+    public Uri getVerificationURI() {
+        return mVerificationURI;
+    }
+
+    public Uri getOriginatingURI() {
+        return mOriginatingURI;
+    }
+
+    public Uri getReferrer() {
+        return mReferrer;
+    }
+
+    public ManifestDigest getManifestDigest() {
+        return mManifestDigest;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (!(o instanceof VerificationParams)) {
+            return false;
+        }
+
+        final VerificationParams other = (VerificationParams) o;
+
+        if (mVerificationURI == null && other.mVerificationURI != null) {
+            return false;
+        }
+        if (!mVerificationURI.equals(other.mVerificationURI)) {
+            return false;
+        }
+
+        if (mOriginatingURI == null && other.mOriginatingURI != null) {
+            return false;
+        }
+        if (!mOriginatingURI.equals(other.mOriginatingURI)) {
+            return false;
+        }
+
+        if (mReferrer == null && other.mReferrer != null) {
+            return false;
+        }
+        if (!mReferrer.equals(other.mReferrer)) {
+            return false;
+        }
+
+        if (mManifestDigest == null && other.mManifestDigest != null) {
+            return false;
+        }
+        if (mManifestDigest != null && !mManifestDigest.equals(other.mManifestDigest)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 3;
+
+        hash += 5 * (mVerificationURI==null?1:mVerificationURI.hashCode());
+        hash += 7 * (mOriginatingURI==null?1:mOriginatingURI.hashCode());
+        hash += 11 * (mReferrer==null?1:mReferrer.hashCode());
+        hash += 13 * (mManifestDigest==null?1:mManifestDigest.hashCode());
+
+        return hash;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX);
+
+        sb.append("mVerificationURI=");
+        sb.append(mVerificationURI.toString());
+        sb.append(",mOriginatingURI=");
+        sb.append(mOriginatingURI.toString());
+        sb.append(",mReferrer=");
+        sb.append(mReferrer.toString());
+        sb.append(",mManifestDigest=");
+        sb.append(mManifestDigest.toString());
+        sb.append('}');
+
+        return sb.toString();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mVerificationURI, 0);
+        dest.writeParcelable(mOriginatingURI, 0);
+        dest.writeParcelable(mReferrer, 0);
+        dest.writeParcelable(mManifestDigest, 0);
+    }
+
+
+    private VerificationParams(Parcel source) {
+        mVerificationURI = source.readParcelable(Uri.class.getClassLoader());
+        mOriginatingURI = source.readParcelable(Uri.class.getClassLoader());
+        mReferrer = source.readParcelable(Uri.class.getClassLoader());
+        mManifestDigest = source.readParcelable(ManifestDigest.class.getClassLoader());
+    }
+
+    public static final Parcelable.Creator<VerificationParams> CREATOR =
+            new Parcelable.Creator<VerificationParams>() {
+        public VerificationParams createFromParcel(Parcel source) {
+                return new VerificationParams(source);
+        }
+
+        public VerificationParams[] newArray(int size) {
+            return new VerificationParams[size];
+        }
+    };
+}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index ea13a2a..52b6498 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -35,6 +35,9 @@
  * <pre>Configuration config = getResources().getConfiguration();</pre>
  */
 public final class Configuration implements Parcelable, Comparable<Configuration> {
+    /** @hide */
+    public static final Configuration EMPTY = new Configuration();
+
     /**
      * Current user preference for the scaling factor for fonts, relative
      * to the base density scaling.
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index d2af3e9..7559f1e 100755
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1121,8 +1121,8 @@
          * Return a StyledAttributes holding the values defined by
          * <var>Theme</var> which are listed in <var>attrs</var>.
          * 
-         * <p>Be sure to call StyledAttributes.recycle() when you are done with
-         * the array.
+         * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
+         * with the array.
          * 
          * @param attrs The desired attributes.
          *
@@ -1149,8 +1149,8 @@
          * Return a StyledAttributes holding the values defined by the style
          * resource <var>resid</var> which are listed in <var>attrs</var>.
          * 
-         * <p>Be sure to call StyledAttributes.recycle() when you are done with
-         * the array.
+         * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
+         * with the array.
          * 
          * @param resid The desired style resource.
          * @param attrs The desired attributes in the style.
@@ -1209,8 +1209,8 @@
          * AttributeSet specifies a style class (through the "style" attribute),
          * that style will be applied on top of the base attributes it defines.
          * 
-         * <p>Be sure to call StyledAttributes.recycle() when you are done with
-         * the array.
+         * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
+         * with the array.
          * 
          * <p>When determining the final value of a particular attribute, there
          * are four inputs that come into play:</p>
@@ -1435,9 +1435,12 @@
             int configChanges = 0xfffffff;
             if (config != null) {
                 mTmpConfig.setTo(config);
+                int density = config.densityDpi;
+                if (density == Configuration.DENSITY_DPI_UNDEFINED) {
+                    density = mMetrics.noncompatDensityDpi;
+                }
                 if (mCompatibilityInfo != null) {
-                    mCompatibilityInfo.applyToConfiguration(mMetrics.noncompatDensityDpi,
-                            mTmpConfig);
+                    mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
                 }
                 if (mTmpConfig.locale == null) {
                     mTmpConfig.locale = Locale.getDefault();
@@ -1448,6 +1451,10 @@
             if (mConfiguration.locale == null) {
                 mConfiguration.locale = Locale.getDefault();
             }
+            if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
+                mMetrics.densityDpi = mConfiguration.densityDpi;
+                mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+            }
             mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
 
             String locale = null;
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 281b843..7f3b6b9 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -691,7 +691,7 @@
     }
 
     /**
-     * Give back a previously retrieved StyledAttributes, for later re-use.
+     * Give back a previously retrieved array, for later re-use.
      */
     public void recycle() {
         synchronized (mResources.mTmpValue) {
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 3c70dc6..e0c9d2c 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -26,7 +26,7 @@
  * @see SensorEvent
  *
  */
-public class Sensor {
+public final class Sensor {
 
     /**
      * A constant describing an accelerometer sensor type. See
@@ -202,4 +202,11 @@
         mMaxRange = max;
         mResolution = res;
     }
+
+    @Override
+    public String toString() {
+        return "{Sensor name=\"" + mName + "\", vendor=\"" + mVendor + "\", version=" + mVersion
+                + ", type=" + mType + ", maxRange=" + mMaxRange + ", resolution=" + mResolution
+                + ", power=" + mPower + ", minDelay=" + mMinDelay + "}";
+    }
 }
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 640044b..a73115c 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -17,12 +17,20 @@
 package android.hardware.display;
 
 import android.content.Context;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
+import android.util.SparseArray;
+import android.view.CompatibilityInfoHolder;
+import android.view.Display;
 import android.view.DisplayInfo;
 
+import java.util.ArrayList;
+
 /**
  * Manages the properties, media routing and power state of attached displays.
  * <p>
@@ -34,25 +42,41 @@
  */
 public final class DisplayManager {
     private static final String TAG = "DisplayManager";
+    private static final boolean DEBUG = false;
+
+    private static final int MSG_DISPLAY_ADDED = 1;
+    private static final int MSG_DISPLAY_REMOVED = 2;
+    private static final int MSG_DISPLAY_CHANGED = 3;
 
     private static DisplayManager sInstance;
 
     private final IDisplayManager mDm;
 
+    // Guarded by mDisplayLock
+    private final Object mDisplayLock = new Object();
+    private final ArrayList<DisplayListenerDelegate> mDisplayListeners =
+            new ArrayList<DisplayListenerDelegate>();
+
+
     private DisplayManager(IDisplayManager dm) {
         mDm = dm;
     }
 
     /**
      * Gets an instance of the display manager.
-     * @return The display manager instance.
+     *
+     * @return The display manager instance, may be null early in system startup
+     * before the display manager has been fully initialized.
+     *
      * @hide
      */
     public static DisplayManager getInstance() {
         synchronized (DisplayManager.class) {
             if (sInstance == null) {
                 IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
-                sInstance = new DisplayManager(IDisplayManager.Stub.asInterface(b));
+                if (b != null) {
+                    sInstance = new DisplayManager(IDisplayManager.Stub.asInterface(b));
+                }
             }
             return sInstance;
         }
@@ -74,4 +98,161 @@
             return false;
         }
     }
+
+    /**
+     * Gets information about a logical display.
+     *
+     * The display metrics may be adjusted to provide compatibility
+     * for legacy applications.
+     *
+     * @param displayId The logical display id.
+     * @param applicationContext The application context from which to obtain
+     * compatible metrics.
+     * @return The display object.
+     */
+    public Display getDisplay(int displayId, Context applicationContext) {
+        if (applicationContext == null) {
+            throw new IllegalArgumentException("applicationContext must not be null");
+        }
+
+        CompatibilityInfoHolder cih = null;
+        if (displayId == Display.DEFAULT_DISPLAY) {
+            cih = applicationContext.getCompatibilityInfo();
+        }
+        return getCompatibleDisplay(displayId, cih);
+    }
+
+    /**
+     * Gets information about a logical display.
+     *
+     * The display metrics may be adjusted to provide compatibility
+     * for legacy applications.
+     *
+     * @param displayId The logical display id.
+     * @param cih The compatibility info, or null if none is required.
+     * @return The display object.
+     *
+     * @hide
+     */
+    public Display getCompatibleDisplay(int displayId, CompatibilityInfoHolder cih) {
+        return new Display(displayId, cih);
+    }
+
+    /**
+     * Gets information about a logical display without applying any compatibility metrics.
+     *
+     * @param displayId The logical display id.
+     * @return The display object.
+     *
+     * @hide
+     */
+    public Display getRealDisplay(int displayId) {
+        return getCompatibleDisplay(displayId, null);
+    }
+
+    /**
+     * Registers an display listener to receive notifications about when
+     * displays are added, removed or changed.
+     *
+     * @param listener The listener to register.
+     * @param handler The handler on which the listener should be invoked, or null
+     * if the listener should be invoked on the calling thread's looper.
+     *
+     * @see #unregisterDisplayListener
+     */
+    public void registerDisplayListener(DisplayListener listener, Handler handler) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener must not be null");
+        }
+
+        synchronized (mDisplayLock) {
+            int index = findDisplayListenerLocked(listener);
+            if (index < 0) {
+                mDisplayListeners.add(new DisplayListenerDelegate(listener, handler));
+            }
+        }
+    }
+
+    /**
+     * Unregisters an input device listener.
+     *
+     * @param listener The listener to unregister.
+     *
+     * @see #registerDisplayListener
+     */
+    public void unregisterDisplayListener(DisplayListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener must not be null");
+        }
+
+        synchronized (mDisplayLock) {
+            int index = findDisplayListenerLocked(listener);
+            if (index >= 0) {
+                DisplayListenerDelegate d = mDisplayListeners.get(index);
+                d.removeCallbacksAndMessages(null);
+                mDisplayListeners.remove(index);
+            }
+        }
+    }
+
+    private int findDisplayListenerLocked(DisplayListener listener) {
+        final int numListeners = mDisplayListeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            if (mDisplayListeners.get(i).mListener == listener) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Listens for changes in available display devices.
+     */
+    public interface DisplayListener {
+        /**
+         * Called whenever a logical display has been added to the system.
+         * Use {@link DisplayManager#getDisplay} to get more information about the display.
+         *
+         * @param displayId The id of the logical display that was added.
+         */
+        void onDisplayAdded(int displayId);
+
+        /**
+         * Called whenever a logical display has been removed from the system.
+         *
+         * @param displayId The id of the logical display that was removed.
+         */
+        void onDisplayRemoved(int displayId);
+
+        /**
+         * Called whenever the properties of a logical display have changed.
+         *
+         * @param displayId The id of the logical display that changed.
+         */
+        void onDisplayChanged(int displayId);
+    }
+
+    private static final class DisplayListenerDelegate extends Handler {
+        public final DisplayListener mListener;
+
+        public DisplayListenerDelegate(DisplayListener listener, Handler handler) {
+            super(handler != null ? handler.getLooper() : Looper.myLooper());
+            mListener = listener;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_DISPLAY_ADDED:
+                    mListener.onDisplayAdded(msg.arg1);
+                    break;
+                case MSG_DISPLAY_REMOVED:
+                    mListener.onDisplayRemoved(msg.arg1);
+                    break;
+                case MSG_DISPLAY_CHANGED:
+                    mListener.onDisplayChanged(msg.arg1);
+                    break;
+            }
+        }
+    }
 }
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 9bab797..98bd4f5 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -87,4 +87,12 @@
 
     /* Sets the file path for USB mass storage backing file. */
     void setMassStorageBackingFile(String path);
+
+    /* Allow USB debugging from the attached host. If alwaysAllow is true, add the
+     * the public key to list of host keys that the user has approved.
+     */
+    void allowUsbDebugging(boolean alwaysAllow, String publicKey);
+
+    /* Deny USB debugging from the attached host */
+    void denyUsbDebugging();
 }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index a9de289..d5b9edc 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -39,7 +39,6 @@
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
-import android.view.Display;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -630,7 +629,7 @@
         if (mWindow != null) {
             throw new IllegalStateException("Must be called before onCreate()");
         }
-        if (ActivityManager.isHighEndGfx(new Display(Display.DEFAULT_DISPLAY, null))) {
+        if (ActivityManager.isHighEndGfx()) {
             mHardwareAccelerated = true;
             return true;
         }
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 00438a1..d59fa6a 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -184,8 +184,17 @@
                 if (!TextUtils.equals(apnType, mApnType)) {
                     return;
                 }
-                mNetworkInfo.setSubtype(TelephonyManager.getDefault().getNetworkType(),
-                        TelephonyManager.getDefault().getNetworkTypeName());
+
+                int oldSubtype = mNetworkInfo.getSubtype();
+                int newSubType = TelephonyManager.getDefault().getNetworkType();
+                String subTypeName = TelephonyManager.getDefault().getNetworkTypeName();
+                mNetworkInfo.setSubtype(newSubType, subTypeName);
+                if (newSubType != oldSubtype && mNetworkInfo.isConnected()) {
+                    Message msg = mTarget.obtainMessage(EVENT_NETWORK_SUBTYPE_CHANGED,
+                                                        oldSubtype, 0, mNetworkInfo);
+                    msg.sendToTarget();
+                }
+
                 PhoneConstants.DataState state = Enum.valueOf(PhoneConstants.DataState.class,
                         intent.getStringExtra(PhoneConstants.STATE_KEY));
                 String reason = intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY);
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index 313c174..eae89f1c 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -63,6 +63,12 @@
     public static final int EVENT_RESTORE_DEFAULT_NETWORK = 6;
 
     /**
+     * msg.what = EVENT_NETWORK_SUBTYPE_CHANGED
+     * msg.obj = NetworkInfo object
+     */
+    public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 7;
+
+    /**
      * -------------------------------------------------------------
      * Control Interface
      * -------------------------------------------------------------
diff --git a/core/java/android/net/arp/ArpPeer.java b/core/java/android/net/arp/ArpPeer.java
index 5f68fdf..2013b11 100644
--- a/core/java/android/net/arp/ArpPeer.java
+++ b/core/java/android/net/arp/ArpPeer.java
@@ -58,9 +58,11 @@
         mInterfaceName = interfaceName;
         mMyAddr = myAddr;
 
-        for (int i = 0; i < MAC_ADDR_LENGTH; i++) {
-            mMyMac[i] = (byte) Integer.parseInt(mac.substring(
-                        i*3, (i*3) + 2), 16);
+        if (mac != null) {
+            for (int i = 0; i < MAC_ADDR_LENGTH; i++) {
+                mMyMac[i] = (byte) Integer.parseInt(mac.substring(
+                            i*3, (i*3) + 2), 16);
+            }
         }
 
         if (myAddr instanceof Inet6Address || peer instanceof Inet6Address) {
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index c62715b..7b16f4d 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -115,4 +115,6 @@
     public static final int BATTERY_PLUGGED_AC = 1;
     /** Power source is a USB port. */
     public static final int BATTERY_PLUGGED_USB = 2;
+    /** Power source is wireless. */
+    public static final int BATTERY_PLUGGED_WIRELESS = 4;
 }
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index fcc0ae4..54f2fe3 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -2071,6 +2071,9 @@
                         case BatteryManager.BATTERY_PLUGGED_USB:
                             pw.print("usb");
                             break;
+                        case BatteryManager.BATTERY_PLUGGED_WIRELESS:
+                            pw.print("wireless");
+                            break;
                         default:
                             pw.print(oldPlug);
                             break;
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 7b51119..5d40456 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -82,7 +82,7 @@
      * @hide
      */
     public static final int getOrigCallingUid() {
-        if (UserId.MU_ENABLED) {
+        if (UserHandle.MU_ENABLED) {
             return getOrigCallingUidNative();
         } else {
             return getCallingUid();
@@ -97,7 +97,7 @@
      * @hide
      */
     public static final int getOrigCallingUser() {
-        return UserId.getUserId(getOrigCallingUid());
+        return UserHandle.getUserId(getOrigCallingUid());
     }
 
     /**
diff --git a/core/java/android/os/FactoryTest.java b/core/java/android/os/FactoryTest.java
new file mode 100644
index 0000000..ec99697
--- /dev/null
+++ b/core/java/android/os/FactoryTest.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os;
+
+/**
+ * Provides support for in-place factory test functions.
+ *
+ * This class provides a few properties that alter the normal operation of the system
+ * during factory testing.
+ *
+ * {@hide}
+ */
+public final class FactoryTest {
+    /**
+     * When true, long-press on power should immediately cause the device to
+     * shut down, without prompting the user.
+     */
+    public static boolean isLongPressOnPowerOffEnabled() {
+        return SystemProperties.getInt("factory.long_press_power_off", 0) != 0;
+    }
+}
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 6c1445d..0941d71 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -28,9 +28,6 @@
 import java.util.zip.CRC32;
 import java.util.zip.CheckedInputStream;
 
-import libcore.io.Os;
-import libcore.io.StructStat;
-
 /**
  * Tools for managing files.  Not for public consumption.
  * @hide
@@ -50,60 +47,12 @@
     public static final int S_IROTH = 00004;
     public static final int S_IWOTH = 00002;
     public static final int S_IXOTH = 00001;
-    
-    
-    /**
-     * File status information. This class maps directly to the POSIX stat structure.
-     * @deprecated use {@link StructStat} instead.
-     * @hide
-     */
-    @Deprecated
-    public static final class FileStatus {
-        public int dev;
-        public int ino;
-        public int mode;
-        public int nlink;
-        public int uid;
-        public int gid;
-        public int rdev;
-        public long size;
-        public int blksize;
-        public long blocks;
-        public long atime;
-        public long mtime;
-        public long ctime;
-    }
-    
-    /**
-     * Get the status for the given path. This is equivalent to the POSIX stat(2) system call. 
-     * @param path The path of the file to be stat'd.
-     * @param status Optional argument to fill in. It will only fill in the status if the file
-     * exists. 
-     * @return true if the file exists and false if it does not exist. If you do not have 
-     * permission to stat the file, then this method will return false.
-     * @deprecated use {@link Os#stat(String)} instead.
-     */
-    @Deprecated
-    public static boolean getFileStatus(String path, FileStatus status) {
-        StrictMode.noteDiskRead();
-        return getFileStatusNative(path, status);
-    }
-
-    private static native boolean getFileStatusNative(String path, FileStatus status);
 
     /** Regular expression for safe filenames: no spaces or metacharacters */
     private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+");
 
     public static native int setPermissions(String file, int mode, int uid, int gid);
 
-    /**
-     * @deprecated use {@link Os#stat(String)} instead.
-     */
-    @Deprecated
-    public static native int getPermissions(String file, int[] outPermissions);
-
-    public static native int setUMask(int mask);
-
     /** returns the FAT file system volume ID for the volume mounted 
      * at the given mount point, or -1 for failure
      * @param mountPoint point for FAT volume
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index b892c81..7785368 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -123,6 +123,7 @@
         }
         mQueue = mLooper.mQueue;
         mCallback = null;
+        mAsynchronous = false;
     }
 
     /**
@@ -147,6 +148,7 @@
         }
         mQueue = mLooper.mQueue;
         mCallback = callback;
+        mAsynchronous = false;
     }
 
     /**
@@ -156,6 +158,7 @@
         mLooper = looper;
         mQueue = looper.mQueue;
         mCallback = null;
+        mAsynchronous = false;
     }
 
     /**
@@ -166,6 +169,31 @@
         mLooper = looper;
         mQueue = looper.mQueue;
         mCallback = callback;
+        mAsynchronous = false;
+    }
+
+    /**
+     * Use the provided queue instead of the default one and take a callback
+     * interface in which to handle messages.  Also set whether the handler
+     * should be asynchronous.
+     *
+     * Handlers are synchronous by default unless this constructor is used to make
+     * one that is strictly asynchronous.
+     *
+     * Asynchronous messages represent interrupts or events that do not require global ordering
+     * with represent to synchronous messages.  Asynchronous messages are not subject to
+     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
+     *
+     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
+     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
+     *
+     * @hide
+     */
+    public Handler(Looper looper, Callback callback, boolean async) {
+        mLooper = looper;
+        mQueue = looper.mQueue;
+        mCallback = callback;
+        mAsynchronous = async;
     }
 
     /**
@@ -464,20 +492,15 @@
      *         the looper is quit before the delivery time of the message
      *         occurs then the message will be dropped.
      */
-    public boolean sendMessageAtTime(Message msg, long uptimeMillis)
-    {
-        boolean sent = false;
+    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
         MessageQueue queue = mQueue;
-        if (queue != null) {
-            msg.target = this;
-            sent = queue.enqueueMessage(msg, uptimeMillis);
-        }
-        else {
+        if (queue == null) {
             RuntimeException e = new RuntimeException(
-                this + " sendMessageAtTime() called with no mQueue");
+                    this + " sendMessageAtTime() called with no mQueue");
             Log.w("Looper", e.getMessage(), e);
+            return false;
         }
-        return sent;
+        return enqueueMessage(queue, msg, uptimeMillis);
     }
 
     /**
@@ -492,20 +515,23 @@
      *         message queue.  Returns false on failure, usually because the
      *         looper processing the message queue is exiting.
      */
-    public final boolean sendMessageAtFrontOfQueue(Message msg)
-    {
-        boolean sent = false;
+    public final boolean sendMessageAtFrontOfQueue(Message msg) {
         MessageQueue queue = mQueue;
-        if (queue != null) {
-            msg.target = this;
-            sent = queue.enqueueMessage(msg, 0);
-        }
-        else {
+        if (queue == null) {
             RuntimeException e = new RuntimeException(
                 this + " sendMessageAtTime() called with no mQueue");
             Log.w("Looper", e.getMessage(), e);
+            return false;
         }
-        return sent;
+        return enqueueMessage(queue, msg, 0);
+    }
+
+    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
+        msg.target = this;
+        if (mAsynchronous) {
+            msg.setAsynchronous(true);
+        }
+        return queue.enqueueMessage(msg, uptimeMillis);
     }
 
     /**
@@ -618,5 +644,6 @@
     final MessageQueue mQueue;
     final Looper mLooper;
     final Callback mCallback;
+    final boolean mAsynchronous;
     IMessenger mMessenger;
 }
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 270e9be..7aee644 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -23,27 +23,33 @@
 
 interface IPowerManager
 {
-    // WARNING: changes in acquireWakeLock() signature must be reflected in IPowerManager.cpp/h
-    void acquireWakeLock(int flags, IBinder lock, String tag, in WorkSource ws);
-    void updateWakeLockWorkSource(IBinder lock, in WorkSource ws);
-    void goToSleep(long time);
-    void goToSleepWithReason(long time, int reason);
-    // WARNING: changes in releaseWakeLock() signature must be reflected in IPowerManager.cpp/h
+    // WARNING: The first two methods must remain the first two methods because their
+    // transaction numbers must not change unless IPowerManager.cpp is also updated.
+    void acquireWakeLock(IBinder lock, int flags, String tag, in WorkSource ws);
     void releaseWakeLock(IBinder lock, int flags);
-    void userActivity(long when, boolean noChangeLights);
-    void userActivityWithForce(long when, boolean noChangeLights, boolean force);
-    void clearUserActivityTimeout(long now, long timeout);
-    void setPokeLock(int pokey, IBinder lock, String tag);
-    int getSupportedWakeLockFlags();
-    void setStayOnSetting(int val);
-    void setMaximumScreenOffTimeount(int timeMs);
-    void preventScreenOn(boolean prevent);
+
+    void updateWakeLockWorkSource(IBinder lock, in WorkSource ws);
+    boolean isWakeLockLevelSupported(int level);
+
+    void userActivity(long time, int event, int flags);
+    void wakeUp(long time);
+    void goToSleep(long time, int reason);
+
     boolean isScreenOn();
     void reboot(String reason);
     void crash(String message);
 
-    // sets the brightness of the backlights (screen, keyboard, button) 0-255
-    void setBacklightBrightness(int brightness);
+    void clearUserActivityTimeout(long now, long timeout);
+    void setPokeLock(int pokey, IBinder lock, String tag);
+    void setStayOnSetting(int val);
+    void setMaximumScreenOffTimeoutFromDeviceAdmin(int timeMs);
+    void preventScreenOn(boolean prevent);
+
+    // temporarily overrides the screen brightness settings to allow the user to
+    // see the effect of a settings change without applying it immediately
+    void setTemporaryScreenBrightnessSettingOverride(int brightness);
+    void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float adj);
+
+    // sets the attention light (used by phone app only)
     void setAttentionLight(boolean on, int color);
-    void setAutoBrightnessAdjustment(float adj);
 }
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index cb1b962..c7a8493 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -33,4 +33,6 @@
     void setGuestEnabled(boolean enable);
     boolean isGuestEnabled();
     void wipeUser(int userHandle);
+    int getUserSerialNumber(int userHandle);
+    int getUserHandle(int userSerialNumber);
 }
diff --git a/core/java/android/os/LocalPowerManager.java b/core/java/android/os/LocalPowerManager.java
index 09336c7..519315c 100644
--- a/core/java/android/os/LocalPowerManager.java
+++ b/core/java/android/os/LocalPowerManager.java
@@ -18,25 +18,11 @@
 
 /** @hide */
 public interface LocalPowerManager {
+    // FIXME: Replace poke locks with something else.
+
     public static final int POKE_LOCK_IGNORE_TOUCH_EVENTS = 0x1;
 
     public static final int POKE_LOCK_SHORT_TIMEOUT = 0x2;
     public static final int POKE_LOCK_MEDIUM_TIMEOUT = 0x4;
     public static final int POKE_LOCK_TIMEOUT_MASK = 0x6;
-
-    void goToSleep(long time);
-    
-    // notify power manager when keyboard is opened/closed
-    void setKeyboardVisibility(boolean visible);
-
-    // when the keyguard is up, it manages the power state, and userActivity doesn't do anything.
-    void enableUserActivity(boolean enabled);
-
-    // the same as the method on PowerManager
-    void userActivity(long time, boolean noChangeLights, int eventType);
-
-    boolean isScreenOn();
-
-    void setScreenBrightnessOverride(int brightness);
-    void setButtonBrightnessOverride(int brightness);
 }
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index a757303..a1901a5 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.content.Context;
 import android.util.Log;
 
 /**
@@ -42,8 +43,8 @@
  * wl.release();
  * }
  * </p><p>
- * The following flags are defined, with varying effects on system power.
- * <i>These flags are mutually exclusive - you may only specify one of them.</i>
+ * The following wake lock levels are defined, with varying effects on system power.
+ * <i>These levels are mutually exclusive - you may only specify one of them.</i>
  *
  * <table border="2" width="85%" align="center" frame="hsides" rules="rows">
  *     <thead>
@@ -177,7 +178,7 @@
     /**
      * Wake lock level: Turns the screen off when the proximity sensor activates.
      * <p>
-     * Since not all devices have proximity sensors, use {@link #getSupportedWakeLockFlags}
+     * Since not all devices have proximity sensors, use {@link #isWakeLockLevelSupported}
      * to determine whether this wake lock level is supported.
      * </p>
      *
@@ -227,24 +228,12 @@
     public static final int WAIT_FOR_PROXIMITY_NEGATIVE = 1;
 
     /**
-     * Brightness value to use when battery is low.
-     * @hide
-     */
-    public static final int BRIGHTNESS_LOW_BATTERY = 10;
-
-    /**
      * Brightness value for fully on.
      * @hide
      */
     public static final int BRIGHTNESS_ON = 255;
 
     /**
-     * Brightness value for dim backlight.
-     * @hide
-     */
-    public static final int BRIGHTNESS_DIM = 20;
-
-    /**
      * Brightness value for fully off.
      * @hide
      */
@@ -271,18 +260,77 @@
      */
     public static final int USER_ACTIVITY_EVENT_TOUCH = 2;
 
+    /**
+     * User activity flag: Do not restart the user activity timeout or brighten
+     * the display in response to user activity if it is already dimmed.
+     * @hide
+     */
+    public static final int USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1 << 0;
+
+    /**
+     * Go to sleep reason code: Going to sleep due by user request.
+     * @hide
+     */
+    public static final int GO_TO_SLEEP_REASON_USER = 0;
+
+    /**
+     * Go to sleep reason code: Going to sleep due by request of the
+     * device administration policy.
+     * @hide
+     */
+    public static final int GO_TO_SLEEP_REASON_DEVICE_ADMIN = 1;
+
+    /**
+     * Go to sleep reason code: Going to sleep due to a screen timeout.
+     * @hide
+     */
+    public static final int GO_TO_SLEEP_REASON_TIMEOUT = 2;
+
+    final Context mContext;
     final IPowerManager mService;
     final Handler mHandler;
 
     /**
      * {@hide}
      */
-    public PowerManager(IPowerManager service, Handler handler) {
+    public PowerManager(Context context, IPowerManager service, Handler handler) {
+        mContext = context;
         mService = service;
         mHandler = handler;
     }
 
     /**
+     * Gets the minimum supported screen brightness setting.
+     * The screen may be allowed to become dimmer than this value but
+     * this is the minimum value that can be set by the user.
+     * @hide
+     */
+    public int getMinimumScreenBrightnessSetting() {
+        return mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_screenBrightnessSettingMinimum);
+    }
+
+    /**
+     * Gets the maximum supported screen brightness setting.
+     * The screen may be allowed to become dimmer than this value but
+     * this is the maximum value that can be set by the user.
+     * @hide
+     */
+    public int getMaximumScreenBrightnessSetting() {
+        return mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_screenBrightnessSettingMaximum);
+    }
+
+    /**
+     * Gets the default screen brightness setting.
+     * @hide
+     */
+    public int getDefaultScreenBrightnessSetting() {
+        return mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_screenBrightnessSettingDefault);
+    }
+
+    /**
      * Creates a new wake lock with the specified level and flags.
      * <p>
      * The {@code levelAndFlags} parameter specifies a wake lock level and optional flags
@@ -360,8 +408,10 @@
     /**
      * Notifies the power manager that user activity happened.
      * <p>
-     * Turns the device from whatever state it's in to full on, and resets
-     * the auto-off timer.
+     * Resets the auto-off timer and brightens the screen if the device
+     * is not asleep.  This is what happens normally when a key or the touch
+     * screen is pressed or when some other user activity occurs.
+     * This method does not wake up the device if it has been put to sleep.
      * </p><p>
      * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
      * </p>
@@ -375,10 +425,14 @@
      * We want the device to stay on while the button is down, but we're about
      * to turn off the screen so we don't want the keyboard backlight to turn on again.
      * Otherwise the lights flash on and then off and it looks weird.
+     *
+     * @see #wakeUp
+     * @see #goToSleep
      */
     public void userActivity(long when, boolean noChangeLights) {
         try {
-            mService.userActivity(when, noChangeLights);
+            mService.userActivity(when, USER_ACTIVITY_EVENT_OTHER,
+                    noChangeLights ? USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS : 0);
         } catch (RemoteException e) {
         }
     }
@@ -386,8 +440,8 @@
    /**
      * Forces the device to go to sleep.
      * <p>
-     * Overrides all the wake locks that are held.  This is what happen when the power
-     * key is pressed to turn off the screen.
+     * Overrides all the wake locks that are held.
+     * This is what happens when the power key is pressed to turn off the screen.
      * </p><p>
      * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
      * </p>
@@ -396,10 +450,37 @@
      * {@link SystemClock#uptimeMillis()} time base.  This timestamp is used to correctly
      * order the user activity with other power management functions.  It should be set
      * to the timestamp of the input event that caused the request to go to sleep.
+     *
+     * @see #userActivity
+     * @see #wakeUp
      */
     public void goToSleep(long time) {
         try {
-            mService.goToSleep(time);
+            mService.goToSleep(time, GO_TO_SLEEP_REASON_USER);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Forces the device to wake up from sleep.
+     * <p>
+     * If the device is currently asleep, wakes it up, otherwise does nothing.
+     * This is what happens when the power key is pressed to turn on the screen.
+     * </p><p>
+     * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
+     * </p>
+     *
+     * @param time The time when the request to wake up was issued, in the
+     * {@link SystemClock#uptimeMillis()} time base.  This timestamp is used to correctly
+     * order the user activity with other power management functions.  It should be set
+     * to the timestamp of the input event that caused the request to wake up.
+     *
+     * @see #userActivity
+     * @see #goToSleep
+     */
+    public void wakeUp(long time) {
+        try {
+            mService.wakeUp(time);
         } catch (RemoteException e) {
         }
     }
@@ -416,34 +497,24 @@
      */
     public void setBacklightBrightness(int brightness) {
         try {
-            mService.setBacklightBrightness(brightness);
+            mService.setTemporaryScreenBrightnessSettingOverride(brightness);
         } catch (RemoteException e) {
         }
     }
 
    /**
-     * Returns the set of wake lock levels and flags for {@link #newWakeLock}
-     * that are supported on the device.
-     * <p>
-     * For example, to test to see if the {@link #PROXIMITY_SCREEN_OFF_WAKE_LOCK}
-     * is supported:
-     * {@samplecode
-     * PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
-     * int supportedFlags = pm.getSupportedWakeLockFlags();
-     * boolean proximitySupported = ((supportedFlags & PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)
-     *         == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK);
-     * }
-     * </p>
+     * Returns true if the specified wake lock level is supported.
      *
-     * @return The set of supported WakeLock flags.
+     * @param level The wake lock level to check.
+     * @return True if the specified wake lock level is supported.
      *
      * {@hide}
      */
-    public int getSupportedWakeLockFlags() {
+    public boolean isWakeLockLevelSupported(int level) {
         try {
-            return mService.getSupportedWakeLockFlags();
+            return mService.isWakeLockLevelSupported(level);
         } catch (RemoteException e) {
-            return 0;
+            return false;
         }
     }
 
@@ -593,7 +664,7 @@
                 // been explicitly released by the keyguard.
                 mHandler.removeCallbacks(mReleaser);
                 try {
-                    mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource);
+                    mService.acquireWakeLock(mToken, mFlags, mTag, mWorkSource);
                 } catch (RemoteException e) {
                 }
                 mHeld = true;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 93860aa..3513bdc 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -376,12 +376,13 @@
     public static final ProcessStartResult start(final String processClass,
                                   final String niceName,
                                   int uid, int gid, int[] gids,
-                                  int debugFlags, int targetSdkVersion,
+                                  int debugFlags, int mountExternal,
+                                  int targetSdkVersion,
                                   String seInfo,
                                   String[] zygoteArgs) {
         try {
             return startViaZygote(processClass, niceName, uid, gid, gids,
-                    debugFlags, targetSdkVersion, seInfo, zygoteArgs);
+                    debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
         } catch (ZygoteStartFailedEx ex) {
             Log.e(LOG_TAG,
                     "Starting VM process through Zygote failed");
@@ -553,7 +554,8 @@
                                   final String niceName,
                                   final int uid, final int gid,
                                   final int[] gids,
-                                  int debugFlags, int targetSdkVersion,
+                                  int debugFlags, int mountExternal,
+                                  int targetSdkVersion,
                                   String seInfo,
                                   String[] extraArgs)
                                   throws ZygoteStartFailedEx {
@@ -580,6 +582,11 @@
             if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
                 argsForZygote.add("--enable-assert");
             }
+            if (mountExternal == Zygote.MOUNT_EXTERNAL_SINGLEUSER) {
+                argsForZygote.add("--mount-external-singleuser");
+            } else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) {
+                argsForZygote.add("--mount-external-multiuser");
+            }
             argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
 
             //TODO optionally enable debuger
@@ -648,13 +655,13 @@
     public static final native int myUid();
 
     /**
-     * Returns the identifier of this process's user handle.  This is the
+     * Returns this process's user handle.  This is the
      * user the process is running under.  It is distinct from
      * {@link #myUid()} in that a particular user will have multiple
      * distinct apps running under it each with their own uid.
      */
-    public static final int myUserHandle() {
-        return UserId.getUserId(myUid());
+    public static final UserHandle myUserHandle() {
+        return new UserHandle(UserHandle.getUserId(myUid()));
     }
 
     /**
@@ -662,7 +669,7 @@
      * @hide
      */
     public static final boolean isIsolated() {
-        int uid = UserId.getAppId(myUid());
+        int uid = UserHandle.getAppId(myUid());
         return uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID;
     }
 
diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java
index 90cfa37..c05a974 100644
--- a/core/java/android/os/SELinux.java
+++ b/core/java/android/os/SELinux.java
@@ -1,5 +1,25 @@
+/*
+ * 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.os;
 
+import android.util.Slog;
+
+import java.io.IOException;
+import java.io.File;
 import java.io.FileDescriptor;
 
 /**
@@ -9,6 +29,8 @@
  */
 public class SELinux {
 
+    private static final String TAG = "SELinux";
+
     /**
      * Determine whether SELinux is disabled or enabled.
      * @return a boolean indicating whether SELinux is enabled.
@@ -102,4 +124,53 @@
      * @return a boolean indicating whether permission was granted.
      */
     public static final native boolean checkSELinuxAccess(String scon, String tcon, String tclass, String perm);
+
+    /**
+     * Restores a file to its default SELinux security context.
+     * If the system is not compiled with SELinux, then {@code true}
+     * is automatically returned.
+     * If SELinux is compiled in, but disabled, then {@code true} is
+     * returned.
+     *
+     * @param pathname The pathname of the file to be relabeled.
+     * @return a boolean indicating whether the relabeling succeeded.
+     * @exception NullPointerException if the pathname is a null object.
+     */
+    public static boolean restorecon(String pathname) throws NullPointerException {
+        if (pathname == null) { throw new NullPointerException(); }
+        return native_restorecon(pathname);
+    }
+
+    /**
+     * Restores a file to its default SELinux security context.
+     * If the system is not compiled with SELinux, then {@code true}
+     * is automatically returned.
+     * If SELinux is compiled in, but disabled, then {@code true} is
+     * returned.
+     *
+     * @param pathname The pathname of the file to be relabeled.
+     * @return a boolean indicating whether the relabeling succeeded.
+     */
+    private static native boolean native_restorecon(String pathname);
+
+    /**
+     * Restores a file to its default SELinux security context.
+     * If the system is not compiled with SELinux, then {@code true}
+     * is automatically returned.
+     * If SELinux is compiled in, but disabled, then {@code true} is
+     * returned.
+     *
+     * @param file The File object representing the path to be relabeled.
+     * @return a boolean indicating whether the relabeling succeeded.
+     * @exception NullPointerException if the file is a null object.
+     */
+    public static boolean restorecon(File file) throws NullPointerException {
+        try {
+            return native_restorecon(file.getCanonicalPath());
+        } catch (IOException e) {
+            Slog.e(TAG, "Error getting canonical path. Restorecon failed for " +
+                   file.getPath(), e);
+            return false;
+        }
+    }
 }
diff --git a/core/java/android/os/StatFs.java b/core/java/android/os/StatFs.java
index 912bfdf..ca7fdba 100644
--- a/core/java/android/os/StatFs.java
+++ b/core/java/android/os/StatFs.java
@@ -16,59 +16,77 @@
 
 package android.os;
 
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+import libcore.io.StructStatFs;
+
 /**
- * Retrieve overall information about the space on a filesystem.  This is a
- * Wrapper for Unix statfs().
+ * Retrieve overall information about the space on a filesystem. This is a
+ * wrapper for Unix statfs().
  */
 public class StatFs {
-    /**
-     * Construct a new StatFs for looking at the stats of the
-     * filesystem at <var>path</var>.  Upon construction, the stat of
-     * the file system will be performed, and the values retrieved available
-     * from the methods on this class.
-     * 
-     * @param path A path in the desired file system to state.
-     */
-    public StatFs(String path) { native_setup(path); }
-    
-    /**
-     * Perform a restat of the file system referenced by this object.  This
-     * is the same as re-constructing the object with the same file system
-     * path, and the new stat values are available upon return.
-     */
-    public void restat(String path) { native_restat(path); }
-
-    @Override
-    protected void finalize() { native_finalize(); }
+    private StructStatFs mStat;
 
     /**
-     * The size, in bytes, of a block on the file system.  This corresponds
-     * to the Unix statfs.f_bsize field.
+     * Construct a new StatFs for looking at the stats of the filesystem at
+     * {@code path}. Upon construction, the stat of the file system will be
+     * performed, and the values retrieved available from the methods on this
+     * class.
+     *
+     * @param path path in the desired file system to stat.
      */
-    public native int getBlockSize();
+    public StatFs(String path) {
+        mStat = doStat(path);
+    }
+
+    private static StructStatFs doStat(String path) {
+        try {
+            return Libcore.os.statfs(path);
+        } catch (ErrnoException e) {
+            throw new IllegalArgumentException("Invalid path: " + path, e);
+        }
+    }
 
     /**
-     * The total number of blocks on the file system.  This corresponds
-     * to the Unix statfs.f_blocks field.
+     * Perform a restat of the file system referenced by this object. This is
+     * the same as re-constructing the object with the same file system path,
+     * and the new stat values are available upon return.
      */
-    public native int getBlockCount();
+    public void restat(String path) {
+        mStat = doStat(path);
+    }
+
+    /**
+     * The size, in bytes, of a block on the file system. This corresponds to
+     * the Unix {@code statfs.f_bsize} field.
+     */
+    public int getBlockSize() {
+        return (int) mStat.f_bsize;
+    }
+
+    /**
+     * The total number of blocks on the file system. This corresponds to the
+     * Unix {@code statfs.f_blocks} field.
+     */
+    public int getBlockCount() {
+        return (int) 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 statfs.f_bfree field.  Most applications will
-     * want to use {@link #getAvailableBlocks()} instead.
+     * 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.
      */
-    public native int getFreeBlocks();
+    public int getFreeBlocks() {
+        return (int) mStat.f_bfree;
+    }
 
     /**
      * The number of blocks that are free on the file system and available to
-     * applications.  This corresponds to the Unix statfs.f_bavail field.
+     * applications. This corresponds to the Unix {@code statfs.f_bavail} field.
      */
-    public native int getAvailableBlocks();    
-    
-    private int mNativeContext;
-    private native void native_restat(String path);
-    private native void native_setup(String path);
-    private native void native_finalize();
+    public int getAvailableBlocks() {
+        return (int) mStat.f_bavail;
+    }
 }
diff --git a/core/java/android/os/UEventObserver.java b/core/java/android/os/UEventObserver.java
index b924e84..d33382b 100644
--- a/core/java/android/os/UEventObserver.java
+++ b/core/java/android/os/UEventObserver.java
@@ -37,14 +37,79 @@
  * @hide
 */
 public abstract class UEventObserver {
-    private static final String TAG = UEventObserver.class.getSimpleName();
+    private static UEventThread sThread;
+
+    private static native void native_setup();
+    private static native int next_event(byte[] buffer);
+
+    public UEventObserver() {
+    }
+
+    protected void finalize() throws Throwable {
+        try {
+            stopObserving();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    private static UEventThread getThread() {
+        synchronized (UEventObserver.class) {
+            if (sThread == null) {
+                sThread = new UEventThread();
+                sThread.start();
+            }
+            return sThread;
+        }
+    }
+
+    private static UEventThread peekThread() {
+        synchronized (UEventObserver.class) {
+            return sThread;
+        }
+    }
+
+    /**
+     * Begin observation of UEvent's.<p>
+     * This method will cause the UEvent thread to start if this is the first
+     * invocation of startObserving in this process.<p>
+     * Once called, the UEvent thread will call onUEvent() when an incoming
+     * UEvent matches the specified string.<p>
+     * This method can be called multiple times to register multiple matches.
+     * Only one call to stopObserving is required even with multiple registered
+     * matches.
+     * @param match A substring of the UEvent to match. Use "" to match all
+     *              UEvent's
+     */
+    public final void startObserving(String match) {
+        final UEventThread t = getThread();
+        t.addObserver(match, this);
+    }
+
+    /**
+     * End observation of UEvent's.<p>
+     * This process's UEvent thread will never call onUEvent() on this
+     * UEventObserver after this call. Repeated calls have no effect.
+     */
+    public final void stopObserving() {
+        final UEventThread t = getThread();
+        if (t != null) {
+            t.removeObserver(this);
+        }
+    }
+
+    /**
+     * Subclasses of UEventObserver should override this method to handle
+     * UEvents.
+     */
+    public abstract void onUEvent(UEvent event);
 
     /**
      * Representation of a UEvent.
      */
-    static public class UEvent {
+    public static final class UEvent {
         // collection of key=value pairs parsed from the uevent message
-        public HashMap<String,String> mMap = new HashMap<String,String>();
+        private final HashMap<String,String> mMap = new HashMap<String,String>();
 
         public UEvent(String message) {
             int offset = 0;
@@ -79,20 +144,20 @@
         }
     }
 
-    private static UEventThread sThread;
-    private static boolean sThreadStarted = false;
-
-    private static class UEventThread extends Thread {
+    private static final class UEventThread extends Thread {
         /** Many to many mapping of string match to observer.
          *  Multimap would be better, but not available in android, so use
          *  an ArrayList where even elements are the String match and odd
          *  elements the corresponding UEventObserver observer */
-        private ArrayList<Object> mObservers = new ArrayList<Object>();
-        
-        UEventThread() {
+        private final ArrayList<Object> mKeysAndObservers = new ArrayList<Object>();
+
+        private final ArrayList<UEventObserver> mTempObserversToSignal =
+                new ArrayList<UEventObserver>();
+
+        public UEventThread() {
             super("UEventObserver");
         }
-        
+
         public void run() {
             native_setup();
 
@@ -101,91 +166,54 @@
             while (true) {
                 len = next_event(buffer);
                 if (len > 0) {
-                    String bufferStr = new String(buffer, 0, len);  // easier to search a String
-                    synchronized (mObservers) {
-                        for (int i = 0; i < mObservers.size(); i += 2) {
-                            if (bufferStr.indexOf((String)mObservers.get(i)) != -1) {
-                                ((UEventObserver)mObservers.get(i+1))
-                                        .onUEvent(new UEvent(bufferStr));
-                            }
-                        }
-                    }
+                    sendEvent(new String(buffer, 0, len));
                 }
             }
         }
-        public void addObserver(String match, UEventObserver observer) {
-            synchronized(mObservers) {
-                mObservers.add(match);
-                mObservers.add(observer);
+
+        private void sendEvent(String message) {
+            synchronized (mKeysAndObservers) {
+                final int N = mKeysAndObservers.size();
+                for (int i = 0; i < N; i += 2) {
+                    final String key = (String)mKeysAndObservers.get(i);
+                    if (message.indexOf(key) != -1) {
+                        final UEventObserver observer =
+                                (UEventObserver)mKeysAndObservers.get(i + 1);
+                        mTempObserversToSignal.add(observer);
+                    }
+                }
+            }
+
+            if (!mTempObserversToSignal.isEmpty()) {
+                final UEvent event = new UEvent(message);
+                final int N = mTempObserversToSignal.size();
+                for (int i = 0; i < N; i++) {
+                    final UEventObserver observer = mTempObserversToSignal.get(i);
+                    observer.onUEvent(event);
+                }
+                mTempObserversToSignal.clear();
             }
         }
+
+        public void addObserver(String match, UEventObserver observer) {
+            synchronized (mKeysAndObservers) {
+                mKeysAndObservers.add(match);
+                mKeysAndObservers.add(observer);
+            }
+        }
+
         /** Removes every key/value pair where value=observer from mObservers */
         public void removeObserver(UEventObserver observer) {
-            synchronized(mObservers) {
-                boolean found = true;
-                while (found) {
-                    found = false;
-                    for (int i = 0; i < mObservers.size(); i += 2) {
-                        if (mObservers.get(i+1) == observer) {
-                            mObservers.remove(i+1);
-                            mObservers.remove(i);
-                            found = true;
-                            break;
-                        }
+            synchronized (mKeysAndObservers) {
+                for (int i = 0; i < mKeysAndObservers.size(); ) {
+                    if (mKeysAndObservers.get(i + 1) == observer) {
+                        mKeysAndObservers.remove(i + 1);
+                        mKeysAndObservers.remove(i);
+                    } else {
+                        i += 2;
                     }
                 }
             }
         }
     }
-
-    private static native void native_setup();
-    private static native int next_event(byte[] buffer);
-
-    private static final synchronized void ensureThreadStarted() {
-        if (sThreadStarted == false) {
-            sThread = new UEventThread();
-            sThread.start();
-            sThreadStarted = true;
-        }
-    }
-
-    /**
-     * Begin observation of UEvent's.<p>
-     * This method will cause the UEvent thread to start if this is the first
-     * invocation of startObserving in this process.<p>
-     * Once called, the UEvent thread will call onUEvent() when an incoming
-     * UEvent matches the specified string.<p>
-     * This method can be called multiple times to register multiple matches.
-     * Only one call to stopObserving is required even with multiple registered
-     * matches.
-     * @param match A substring of the UEvent to match. Use "" to match all
-     *              UEvent's
-     */
-    public final synchronized void startObserving(String match) {
-        ensureThreadStarted();
-        sThread.addObserver(match, this);
-    }
-
-    /**
-     * End observation of UEvent's.<p>
-     * This process's UEvent thread will never call onUEvent() on this
-     * UEventObserver after this call. Repeated calls have no effect.
-     */
-    public final synchronized void stopObserving() {
-        sThread.removeObserver(this);
-    }
-
-    /**
-     * Subclasses of UEventObserver should override this method to handle
-     * UEvents.
-     */
-    public abstract void onUEvent(UEvent event);
-
-    protected void finalize() throws Throwable {
-        try {
-            stopObserving();
-        } finally {
-            super.finalize();
-        }
-    }
 }
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
new file mode 100644
index 0000000..0843d85
--- /dev/null
+++ b/core/java/android/os/UserHandle.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * Representation of a user on the device.
+ */
+public final class UserHandle implements Parcelable {
+    /**
+     * @hide Range of uids allocated for a user.
+     */
+    public static final int PER_USER_RANGE = 100000;
+
+    /** @hide A user id to indicate all users on the device */
+    public static final int USER_ALL = -1;
+
+    /** @hide A user id to indicate the currently active user */
+    public static final int USER_CURRENT = -2;
+
+    /** @hide An undefined user id */
+    public static final int USER_NULL = -10000;
+
+    /** @hide A user id constant to indicate the "owner" user of the device */
+    public static final int USER_OWNER = 0;
+
+    /**
+     * @hide Enable multi-user related side effects. Set this to false if
+     * there are problems with single user use-cases.
+     */
+    public static final boolean MU_ENABLED = true;
+
+    final int mHandle;
+
+    /**
+     * Checks to see if the user id is the same for the two uids, i.e., they belong to the same
+     * user.
+     * @hide
+     */
+    public static final boolean isSameUser(int uid1, int uid2) {
+        return getUserId(uid1) == getUserId(uid2);
+    }
+
+    /**
+     * Checks to see if both uids are referring to the same app id, ignoring the user id part of the
+     * uids.
+     * @param uid1 uid to compare
+     * @param uid2 other uid to compare
+     * @return whether the appId is the same for both uids
+     * @hide
+     */
+    public static final boolean isSameApp(int uid1, int uid2) {
+        return getAppId(uid1) == getAppId(uid2);
+    }
+
+    /** @hide */
+    public static final boolean isIsolated(int uid) {
+        uid = getAppId(uid);
+        return uid >= Process.FIRST_ISOLATED_UID && uid <= Process.LAST_ISOLATED_UID;
+    }
+
+    /** @hide */
+    public static boolean isApp(int uid) {
+        if (uid > 0) {
+            uid = UserHandle.getAppId(uid);
+            return uid >= Process.FIRST_APPLICATION_UID && uid <= Process.LAST_APPLICATION_UID;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns the user id for a given uid.
+     * @hide
+     */
+    public static final int getUserId(int uid) {
+        if (MU_ENABLED) {
+            return uid / PER_USER_RANGE;
+        } else {
+            return 0;
+        }
+    }
+
+    /** @hide */
+    public static final int getCallingUserId() {
+        return getUserId(Binder.getCallingUid());
+    }
+
+    /**
+     * Returns the uid that is composed from the userId and the appId.
+     * @hide
+     */
+    public static final int getUid(int userId, int appId) {
+        if (MU_ENABLED) {
+            return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
+        } else {
+            return appId;
+        }
+    }
+
+    /**
+     * Returns the app id (or base uid) for a given uid, stripping out the user id from it.
+     * @hide
+     */
+    public static final int getAppId(int uid) {
+        return uid % PER_USER_RANGE;
+    }
+
+    /**
+     * Returns the user id of the current process
+     * @return user id of the current process
+     * @hide
+     */
+    public static final int myUserId() {
+        return getUserId(Process.myUid());
+    }
+
+    /** @hide */
+    public UserHandle(int h) {
+        mHandle = h;
+    }
+
+    /** @hide */
+    public int getIdentifier() {
+        return mHandle;
+    }
+
+    @Override
+    public String toString() {
+        return "UserHandle{" + mHandle + "}";
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        try {
+            if (obj != null) {
+                UserHandle other = (UserHandle)obj;
+                return mHandle == other.mHandle;
+            }
+        } catch (ClassCastException e) {
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return mHandle;
+    }
+    
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mHandle);
+    }
+
+    /**
+     * Write a UserHandle to a Parcel, handling null pointers.  Must be
+     * read with {@link #readFromParcel(Parcel)}.
+     * 
+     * @param h The UserHandle to be written.
+     * @param out The Parcel in which the UserHandle will be placed.
+     * 
+     * @see #readFromParcel(Parcel)
+     */
+    public static void writeToParcel(UserHandle h, Parcel out) {
+        if (h != null) {
+            h.writeToParcel(out, 0);
+        } else {
+            out.writeInt(USER_NULL);
+        }
+    }
+    
+    /**
+     * Read a UserHandle from a Parcel that was previously written
+     * with {@link #writeToParcel(UserHandle, Parcel)}, returning either
+     * a null or new object as appropriate.
+     * 
+     * @param in The Parcel from which to read the UserHandle
+     * @return Returns a new UserHandle matching the previously written
+     * object, or null if a null had been written.
+     * 
+     * @see #writeToParcel(UserHandle, Parcel)
+     */
+    public static UserHandle readFromParcel(Parcel in) {
+        int h = in.readInt();
+        return h != USER_NULL ? new UserHandle(h) : null;
+    }
+    
+    public static final Parcelable.Creator<UserHandle> CREATOR
+            = new Parcelable.Creator<UserHandle>() {
+        public UserHandle createFromParcel(Parcel in) {
+            return new UserHandle(in);
+        }
+
+        public UserHandle[] newArray(int size) {
+            return new UserHandle[size];
+        }
+    };
+
+    /**
+     * Instantiate a new UserHandle from the data in a Parcel that was
+     * previously written with {@link #writeToParcel(Parcel, int)}.  Note that you
+     * must not use this with data written by
+     * {@link #writeToParcel(UserHandle, Parcel)} since it is not possible
+     * to handle a null UserHandle here.
+     * 
+     * @param in The Parcel containing the previously written UserHandle,
+     * positioned at the location in the buffer where it was written.
+     */
+    public UserHandle(Parcel in) {
+        mHandle = in.readInt();
+    }
+}
diff --git a/core/java/android/os/UserId.java b/core/java/android/os/UserId.java
deleted file mode 100644
index 7e611df..0000000
--- a/core/java/android/os/UserId.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-/**
- * @hide
- */
-public final class UserId {
-    /**
-     * Range of IDs allocated for a user.
-     *
-     * @hide
-     */
-    public static final int PER_USER_RANGE = 100000;
-
-    /** A user id to indicate all users on the device */
-    public static final int USER_ALL = -1;
-
-    /** A user id to indicate the currently active user */
-    public static final int USER_CURRENT = -2;
-
-
-    /**
-     * Enable multi-user related side effects. Set this to false if there are problems with single
-     * user usecases.
-     * */
-    public static final boolean MU_ENABLED = true;
-
-    /**
-     * Checks to see if the user id is the same for the two uids, i.e., they belong to the same
-     * user.
-     * @hide
-     */
-    public static final boolean isSameUser(int uid1, int uid2) {
-        return getUserId(uid1) == getUserId(uid2);
-    }
-
-    /**
-     * Checks to see if both uids are referring to the same app id, ignoring the user id part of the
-     * uids.
-     * @param uid1 uid to compare
-     * @param uid2 other uid to compare
-     * @return whether the appId is the same for both uids
-     * @hide
-     */
-    public static final boolean isSameApp(int uid1, int uid2) {
-        return getAppId(uid1) == getAppId(uid2);
-    }
-
-    public static final boolean isIsolated(int uid) {
-        uid = getAppId(uid);
-        return uid >= Process.FIRST_ISOLATED_UID && uid <= Process.LAST_ISOLATED_UID;
-    }
-
-    public static boolean isApp(int uid) {
-        if (uid > 0) {
-            uid = UserId.getAppId(uid);
-            return uid >= Process.FIRST_APPLICATION_UID && uid <= Process.LAST_APPLICATION_UID;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Returns the user id for a given uid.
-     * @hide
-     */
-    public static final int getUserId(int uid) {
-        if (MU_ENABLED) {
-            return uid / PER_USER_RANGE;
-        } else {
-            return 0;
-        }
-    }
-
-    public static final int getCallingUserId() {
-        return getUserId(Binder.getCallingUid());
-    }
-
-    /**
-     * Returns the uid that is composed from the userId and the appId.
-     * @hide
-     */
-    public static final int getUid(int userId, int appId) {
-        if (MU_ENABLED) {
-            return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
-        } else {
-            return appId;
-        }
-    }
-
-    /**
-     * Returns the app id (or base uid) for a given uid, stripping out the user id from it.
-     * @hide
-     */
-    public static final int getAppId(int uid) {
-        return uid % PER_USER_RANGE;
-    }
-
-    /**
-     * Returns the user id of the current process
-     * @return user id of the current process
-     */
-    public static final int myUserId() {
-        return getUserId(Process.myUid());
-    }
-}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 9c73392..de8e78c 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -51,11 +51,12 @@
      * @hide
      * */
     public int getUserHandle() {
-        return Process.myUserHandle();
+        return UserHandle.myUserId();
     }
 
     /**
      * Returns the user name of the user making this call.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @return the user name
      */
     public String getUserName() {
@@ -69,6 +70,7 @@
 
     /**
      * Returns the UserInfo object describing a specific user.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @param userHandle the user handle of the user whose information is being requested.
      * @return the UserInfo object for a specific user.
      * @hide
@@ -84,6 +86,7 @@
 
     /**
      * Creates a user with the specified name and options.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      *
      * @param name the user's name
      * @param flags flags that identify the type of user and other properties.
@@ -103,6 +106,7 @@
 
     /**
      * Returns information for all users on this device.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @return the list of users that were created.
      * @hide
      */
@@ -117,6 +121,7 @@
 
     /**
      * Removes a user and all associated data.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @param userHandle the integer handle of the user, where 0 is the primary user.
      * @hide
      */
@@ -131,6 +136,7 @@
 
     /**
      * Updates the user's name.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      *
      * @param userHandle the user's integer handle
      * @param name the new name for the user
@@ -162,6 +168,7 @@
     /**
      * Enable or disable the use of a guest account. If disabled, the existing guest account
      * will be wiped.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @param enable whether to enable a guest account.
      * @hide
      */
@@ -175,6 +182,7 @@
 
     /**
      * Checks if a guest user is enabled for this device.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @return whether a guest user is enabled
      * @hide
      */
@@ -189,6 +197,7 @@
 
     /**
      * Wipes all the data for a user, but doesn't remove the user.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @param userHandle
      * @hide
      */
@@ -209,4 +218,40 @@
     public int getMaxSupportedUsers() {
         return mContext.getResources().getInteger(R.integer.config_multiuserMaximumUsers);
     }
+
+    /**
+     * Returns a serial number on this device for a given userHandle. User handles can be recycled
+     * when deleting and creating users, but serial numbers are not reused until the device is wiped.
+     * @param userHandle
+     * @return a serial number associated with that user, or -1 if the userHandle is not valid.
+     * @hide
+     */
+    public int getUserSerialNumber(int userHandle) {
+        try {
+            return mService.getUserSerialNumber(userHandle);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get serial number for user " + userHandle);
+        }
+        return -1;
+    }
+
+    /**
+     * Returns a userHandle on this device for a given user serial number. User handles can be
+     * recycled when deleting and creating users, but serial numbers are not reused until the device
+     * is wiped.
+     * @param userSerialNumber
+     * @return the userHandle associated with that user serial number, or -1 if the serial number
+     * is not valid.
+     * @hide
+     */
+    public int getUserHandle(int userSerialNumber) {
+        try {
+            return mService.getUserHandle(userSerialNumber);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get userHandle for user " + userSerialNumber);
+        }
+        return -1;
+    }
+
+
 }
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index a85f4fa..ba77df7 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -1,5 +1,9 @@
 package android.os;
 
+import com.android.internal.util.ArrayUtils;
+
+import java.util.Arrays;
+
 /**
  * Describes the source of some work that may be done by someone else.
  * Currently the public representation of what a work source is is not
@@ -313,6 +317,20 @@
         dest.writeIntArray(mUids);
     }
 
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("{WorkSource: uids=[");
+        for (int i = 0; i < mNum; i++) {
+            if (i != 0) {
+                result.append(", ");
+            }
+            result.append(mUids[i]);
+        }
+        result.append("]}");
+        return result.toString();
+    }
+
     public static final Parcelable.Creator<WorkSource> CREATOR
             = new Parcelable.Creator<WorkSource>() {
         public WorkSource createFromParcel(Parcel in) {
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 22b68bc..5dca67f 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -17,9 +17,6 @@
 
 package android.provider;
 
-import com.android.internal.telephony.CallerInfo;
-import com.android.internal.telephony.PhoneConstants;
-
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -30,6 +27,9 @@
 import android.provider.ContactsContract.DataUsageFeedback;
 import android.text.TextUtils;
 
+import com.android.internal.telephony.CallerInfo;
+import com.android.internal.telephony.PhoneConstants;
+
 /**
  * The CallLog provider contains information about placed and received calls.
  */
@@ -59,6 +59,20 @@
                 Uri.parse("content://call_log/calls/filter");
 
         /**
+         * Query parameter used to limit the number of call logs returned.
+         * <p>
+         * TYPE: integer
+         */
+        public static final String LIMIT_PARAM_KEY = "limit";
+
+        /**
+         * Query parameter used to specify the starting record to return.
+         * <p>
+         * TYPE: integer
+         */
+        public static final String OFFSET_PARAM_KEY = "offset";
+
+        /**
          * An optional URI parameter which instructs the provider to allow the operation to be
          * applied to voicemail records as well.
          * <p>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 01252f0..28273f0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -41,7 +41,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.speech.tts.TextToSpeech;
 import android.text.TextUtils;
 import android.util.AndroidException;
@@ -1147,6 +1147,7 @@
          * <li>{@code 0} to never stay on while plugged in</li>
          * <li>{@link BatteryManager#BATTERY_PLUGGED_AC} to stay on for AC charger</li>
          * <li>{@link BatteryManager#BATTERY_PLUGGED_USB} to stay on for USB charger</li>
+         * <li>{@link BatteryManager#BATTERY_PLUGGED_WIRELESS} to stay on for wireless charger</li>
          * </ul>
          * These values can be OR-ed together.
          */
@@ -1381,7 +1382,9 @@
 
         /**
          * Whether or not to dim the screen. 0=no  1=yes
+         * @deprecated This setting is no longer used.
          */
+        @Deprecated
         public static final String DIM_SCREEN = "dim_screen";
 
         /**
@@ -2334,7 +2337,7 @@
             if (sLockSettings != null && !sIsSystemProcess
                     && MOVED_TO_LOCK_SETTINGS.contains(name)) {
                 try {
-                    return sLockSettings.getString(name, "0", UserId.getCallingUserId());
+                    return sLockSettings.getString(name, "0", UserHandle.getCallingUserId());
                 } catch (RemoteException re) {
                     // Fall through
                 }
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index a1f6735..df85b2f 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -18,6 +18,9 @@
 
 import com.android.internal.content.PackageMonitor;
 
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
 import android.app.ISearchManager;
 import android.app.SearchManager;
 import android.app.SearchableInfo;
@@ -27,14 +30,18 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
 import android.os.Binder;
 import android.os.Process;
-import android.os.UserId;
+import android.os.RemoteException;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.util.Log;
+import android.util.Slog;
 import android.util.SparseArray;
 
 import java.util.List;
@@ -179,32 +186,76 @@
             Log.e(TAG, "getSearchableInfo(), activity == null");
             return null;
         }
-        return getSearchables(UserId.getCallingUserId()).getSearchableInfo(launchActivity);
+        return getSearchables(UserHandle.getCallingUserId()).getSearchableInfo(launchActivity);
     }
 
     /**
      * Returns a list of the searchable activities that can be included in global search.
      */
     public List<SearchableInfo> getSearchablesInGlobalSearch() {
-        return getSearchables(UserId.getCallingUserId()).getSearchablesInGlobalSearchList();
+        return getSearchables(UserHandle.getCallingUserId()).getSearchablesInGlobalSearchList();
     }
 
     public List<ResolveInfo> getGlobalSearchActivities() {
-        return getSearchables(UserId.getCallingUserId()).getGlobalSearchActivities();
+        return getSearchables(UserHandle.getCallingUserId()).getGlobalSearchActivities();
     }
 
     /**
      * Gets the name of the global search activity.
      */
     public ComponentName getGlobalSearchActivity() {
-        return getSearchables(UserId.getCallingUserId()).getGlobalSearchActivity();
+        return getSearchables(UserHandle.getCallingUserId()).getGlobalSearchActivity();
     }
 
     /**
      * Gets the name of the web search activity.
      */
     public ComponentName getWebSearchActivity() {
-        return getSearchables(UserId.getCallingUserId()).getWebSearchActivity();
+        return getSearchables(UserHandle.getCallingUserId()).getWebSearchActivity();
     }
 
+    @Override
+    public ComponentName getAssistIntent(int userHandle) {
+        try {
+            if (userHandle != UserHandle.getCallingUserId()) {
+                // Requesting a different user, make sure that they have the permission
+                if (ActivityManager.checkComponentPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                        Binder.getCallingUid(), -1, true)
+                        == PackageManager.PERMISSION_GRANTED) {
+                    // Translate to the current user id, if caller wasn't aware
+                    if (userHandle == UserHandle.USER_CURRENT) {
+                        long identity = Binder.clearCallingIdentity();
+                        userHandle = ActivityManagerNative.getDefault().getCurrentUser().id;
+                        Binder.restoreCallingIdentity(identity);
+                    }
+                } else {
+                    String msg = "Permission Denial: "
+                            + "Request to getAssistIntent for " + userHandle
+                            + " but is calling from user " + UserHandle.getCallingUserId()
+                            + "; this requires "
+                            + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+                    Slog.w(TAG, msg);
+                    return null;
+                }
+            }
+            IPackageManager pm = AppGlobals.getPackageManager();
+            Intent assistIntent = new Intent(Intent.ACTION_ASSIST);
+            ResolveInfo info =
+                    pm.resolveIntent(assistIntent,
+                    assistIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
+                    PackageManager.MATCH_DEFAULT_ONLY, userHandle);
+            if (info != null) {
+                return new ComponentName(
+                        info.activityInfo.applicationInfo.packageName,
+                        info.activityInfo.name);
+            }
+        } catch (RemoteException re) {
+            // Local call
+            Log.e(TAG, "RemoteException in getAssistIntent: " + re);
+        } catch (Exception e) {
+            Log.e(TAG, "Exception in getAssistIntent: " + e);
+        }
+        return null;
+    }
 }
diff --git a/core/java/android/service/dreams/DreamManagerService.java b/core/java/android/service/dreams/DreamManagerService.java
index dd177cb..5d6b17e 100644
--- a/core/java/android/service/dreams/DreamManagerService.java
+++ b/core/java/android/service/dreams/DreamManagerService.java
@@ -18,6 +18,7 @@
 import android.util.Slog;
 import android.view.IWindowManager;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 
 /**
  *
@@ -44,8 +45,7 @@
     public DreamManagerService(Context context) {
         if (DEBUG) Slog.v(TAG, "DreamManagerService startup");
         mContext = context;
-        mIWindowManager = IWindowManager.Stub.asInterface(
-                ServiceManager.getService(Context.WINDOW_SERVICE));
+        mIWindowManager = WindowManagerGlobal.getWindowManagerService();
     }
 
     private void checkPermission(String permission) {
@@ -123,7 +123,9 @@
     // IDreamManager method
     @Override
     public boolean isDreaming() {
-        return mCurrentDream != null;
+        synchronized (mLock) {
+            return mCurrentDreamToken != null;
+        }
     }
 
     public void bindDreamComponentL(ComponentName componentName, boolean test) {
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index b513915..efa8911 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -36,7 +36,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
-import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.LogPrinter;
@@ -51,9 +50,8 @@
 import android.view.SurfaceHolder;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewRootImpl;
 import android.view.WindowManager;
-import android.view.WindowManagerImpl;
+import android.view.WindowManagerGlobal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -674,8 +672,8 @@
                             }
                         }
 
-                        redrawNeeded |= creating
-                                || (relayoutResult&WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0;
+                        redrawNeeded |= creating || (relayoutResult
+                                & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0;
 
                         if (forceReport || creating || surfaceCreating
                                 || formatChanged || sizeChanged) {
@@ -762,7 +760,7 @@
             mWindowToken = wrapper.mWindowToken;
             mSurfaceHolder.setSizeFromLayout();
             mInitializing = true;
-            mSession = ViewRootImpl.getWindowSession(getMainLooper());
+            mSession = WindowManagerGlobal.getWindowSession(getMainLooper());
             
             mWindow.setSession(mSession);
 
diff --git a/core/java/android/speech/tts/BlockingAudioTrack.java b/core/java/android/speech/tts/BlockingAudioTrack.java
index fcadad7..47e2129 100644
--- a/core/java/android/speech/tts/BlockingAudioTrack.java
+++ b/core/java/android/speech/tts/BlockingAudioTrack.java
@@ -67,12 +67,10 @@
     private int mAudioBufferSize;
     private int mBytesWritten = 0;
 
-    private AudioTrack mAudioTrack;
+    // Need to be seen by stop() which can be called from another thread. mAudioTrack will be
+    // set to null only after waitAndRelease().
+    private volatile AudioTrack mAudioTrack;
     private volatile boolean mStopped;
-    // Locks the initialization / uninitialization of the audio track.
-    // This is required because stop() will throw an illegal state exception
-    // if called before init() or after mAudioTrack.release().
-    private final Object mAudioTrackLock = new Object();
 
     BlockingAudioTrack(int streamType, int sampleRate,
             int audioFormat, int channelCount,
@@ -93,19 +91,21 @@
         mStopped = false;
     }
 
-    public void init() {
+    public boolean init() {
         AudioTrack track = createStreamingAudioTrack();
+        mAudioTrack = track;
 
-        synchronized (mAudioTrackLock) {
-            mAudioTrack = track;
+        if (track == null) {
+            return false;
+        } else {
+            return true;
         }
     }
 
     public void stop() {
-        synchronized (mAudioTrackLock) {
-            if (mAudioTrack != null) {
-                mAudioTrack.stop();
-            }
+        AudioTrack track = mAudioTrack;
+        if (track != null) {
+            track.stop();
         }
         mStopped = true;
     }
@@ -120,6 +120,12 @@
     }
 
     public void waitAndRelease() {
+        AudioTrack track = mAudioTrack;
+        if (track == null) {
+            if (DBG) Log.d(TAG, "Audio track null [duplicate call to waitAndRelease ?]");
+            return;
+        }
+
         // For "small" audio tracks, we have to stop() them to make them mixable,
         // else the audio subsystem will wait indefinitely for us to fill the buffer
         // before rendering the track mixable.
@@ -129,11 +135,11 @@
         if (mBytesWritten < mAudioBufferSize && !mStopped) {
             if (DBG) {
                 Log.d(TAG, "Stopping audio track to flush audio, state was : " +
-                        mAudioTrack.getPlayState() + ",stopped= " + mStopped);
+                        track.getPlayState() + ",stopped= " + mStopped);
             }
 
             mIsShortUtterance = true;
-            mAudioTrack.stop();
+            track.stop();
         }
 
         // Block until the audio track is done only if we haven't stopped yet.
@@ -145,11 +151,9 @@
         // The last call to AudioTrack.write( ) will return only after
         // all data from the audioTrack has been sent to the mixer, so
         // it's safe to release at this point.
-        if (DBG) Log.d(TAG, "Releasing audio track [" + mAudioTrack.hashCode() + "]");
-        synchronized (mAudioTrackLock) {
-            mAudioTrack.release();
-            mAudioTrack = null;
-        }
+        if (DBG) Log.d(TAG, "Releasing audio track [" + track.hashCode() + "]");
+        track.release();
+        mAudioTrack = null;
     }
 
 
diff --git a/core/java/android/speech/tts/FileSynthesisCallback.java b/core/java/android/speech/tts/FileSynthesisCallback.java
index 04c3377..3e33e8e 100644
--- a/core/java/android/speech/tts/FileSynthesisCallback.java
+++ b/core/java/android/speech/tts/FileSynthesisCallback.java
@@ -95,6 +95,22 @@
         }
     }
 
+    /**
+     * Checks whether a given file exists, and deletes it if it does.
+     */
+    private boolean maybeCleanupExistingFile(File file) {
+        if (file.exists()) {
+            Log.v(TAG, "File " + file + " exists, deleting.");
+            if (!file.delete()) {
+                Log.e(TAG, "Failed to delete " + file);
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+
     @Override
     public int getMaxBufferSize() {
         return MAX_AUDIO_BUFFER_SIZE;
@@ -120,6 +136,11 @@
                 cleanUp();
                 throw new IllegalArgumentException("FileSynthesisRequest.start() called twice");
             }
+
+            if (!maybeCleanupExistingFile(mFileName)) {
+                return TextToSpeech.ERROR;
+            }
+
             mSampleRateInHz = sampleRateInHz;
             mAudioFormat = audioFormat;
             mChannelCount = channelCount;
@@ -166,6 +187,12 @@
     public int done() {
         if (DBG) Log.d(TAG, "FileSynthesisRequest.done()");
         synchronized (mStateLock) {
+            if (mDone) {
+                if (DBG) Log.d(TAG, "Duplicate call to done()");
+                // This preserves existing behaviour. Earlier, if done was called twice
+                // we'd return ERROR because mFile == null and we'd add to logspam.
+                return TextToSpeech.ERROR;
+            }
             if (mStopped) {
                 if (DBG) Log.d(TAG, "Request has been aborted.");
                 return TextToSpeech.ERROR;
diff --git a/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java b/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
index d299d70..e853c9e 100644
--- a/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
+++ b/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
@@ -87,7 +87,10 @@
         dispatcher.dispatchOnStart();
 
 
-        mAudioTrack.init();
+        if (!mAudioTrack.init()) {
+            dispatcher.dispatchOnError();
+            return;
+        }
 
         try {
             byte[] buffer = null;
@@ -242,4 +245,3 @@
         }
     }
 }
-
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 7a174af..5e367cb 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -1282,6 +1282,7 @@
             }
         };
 
+        @Override
         public void onServiceConnected(ComponentName name, IBinder service) {
             Log.i(TAG, "Connected to " + name);
             synchronized(mStartLock) {
@@ -1305,6 +1306,7 @@
             return mCallback;
         }
 
+        @Override
         public void onServiceDisconnected(ComponentName name) {
             synchronized(mStartLock) {
                 mService = null;
@@ -1317,24 +1319,33 @@
 
         public void disconnect() {
             mContext.unbindService(this);
+
+            synchronized (mStartLock) {
+                mService = null;
+                // If this is the active connection, clear it
+                if (mServiceConnection == this) {
+                    mServiceConnection = null;
+                }
+
+            }
         }
 
         public <R> R runAction(Action<R> action, R errorResult, String method, boolean reconnect) {
-            try {
-                synchronized (mStartLock) {
+            synchronized (mStartLock) {
+                try {
                     if (mService == null) {
                         Log.w(TAG, method + " failed: not connected to TTS engine");
                         return errorResult;
                     }
                     return action.run(mService);
+                } catch (RemoteException ex) {
+                    Log.e(TAG, method + " failed", ex);
+                    if (reconnect) {
+                        disconnect();
+                        initTts();
+                    }
+                    return errorResult;
                 }
-            } catch (RemoteException ex) {
-                Log.e(TAG, method + " failed", ex);
-                if (reconnect) {
-                    disconnect();
-                    initTts();
-                }
-                return errorResult;
             }
         }
     }
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 4c1a0afc..d124e68 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -549,7 +549,7 @@
         @Override
         public boolean isValid() {
             if (mText == null) {
-                Log.wtf(TAG, "Got null text");
+                Log.e(TAG, "null synthesis text");
                 return false;
             }
             if (mText.length() >= MAX_SPEECH_ITEM_CHAR_LENGTH) {
@@ -641,14 +641,6 @@
         }
 
         @Override
-        public boolean isValid() {
-            if (!super.isValid()) {
-                return false;
-            }
-            return checkFile(mFile);
-        }
-
-        @Override
         protected AbstractSynthesisCallback createSynthesisCallback() {
             return new FileSynthesisCallback(mFile);
         }
@@ -664,33 +656,6 @@
             }
             return status;
         }
-
-        /**
-         * Checks that the given file can be used for synthesis output.
-         */
-        private boolean checkFile(File file) {
-            try {
-                if (file.exists()) {
-                    Log.v(TAG, "File " + file + " exists, deleting.");
-                    if (!file.delete()) {
-                        Log.e(TAG, "Failed to delete " + file);
-                        return false;
-                    }
-                }
-                if (!file.createNewFile()) {
-                    Log.e(TAG, "Can't create file " + file);
-                    return false;
-                }
-                if (!file.delete()) {
-                    Log.e(TAG, "Failed to delete " + file);
-                    return false;
-                }
-                return true;
-            } catch (IOException e) {
-                Log.e(TAG, "Can't use " + file + " due to exception " + e);
-                return false;
-            }
-        }
     }
 
     private class AudioSpeechItem extends SpeechItem {
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 270624c..987062a 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -27,6 +27,7 @@
 import android.text.style.EasyEditSpan;
 import android.text.style.ForegroundColorSpan;
 import android.text.style.LeadingMarginSpan;
+import android.text.style.LocaleSpan;
 import android.text.style.MetricAffectingSpan;
 import android.text.style.QuoteSpan;
 import android.text.style.RelativeSizeSpan;
@@ -587,6 +588,8 @@
     public static final int SUGGESTION_RANGE_SPAN = 21;
     /** @hide */
     public static final int EASY_EDIT_SPAN = 22;
+    /** @hide */
+    public static final int LOCALE_SPAN = 23;
 
     /**
      * Flatten a CharSequence and whatever styles can be copied across processes
@@ -754,6 +757,10 @@
                     readSpan(p, sp, new EasyEditSpan());
                     break;
 
+                case LOCALE_SPAN:
+                    readSpan(p, sp, new LocaleSpan(p));
+                    break;
+
                 default:
                     throw new RuntimeException("bogus span encoding " + kind);
                 }
@@ -1042,9 +1049,14 @@
                                          float avail, TruncateAt where,
                                          boolean preserveLength,
                                          EllipsizeCallback callback) {
+
+        final String ellipsis = (where == TruncateAt.END_SMALL) ?
+                Resources.getSystem().getString(R.string.ellipsis_two_dots) :
+                Resources.getSystem().getString(R.string.ellipsis);
+
         return ellipsize(text, paint, avail, where, preserveLength, callback,
                 TextDirectionHeuristics.FIRSTSTRONG_LTR,
-                (where == TruncateAt.END_SMALL) ? ELLIPSIS_TWO_DOTS : ELLIPSIS_NORMAL);
+                ellipsis);
     }
 
     /**
@@ -1700,9 +1712,4 @@
     private static String[] EMPTY_STRING_ARRAY = new String[]{};
 
     private static final char ZWNBS_CHAR = '\uFEFF';
-
-    private static final String ELLIPSIS_NORMAL = Resources.getSystem().getString(
-            R.string.ellipsis);
-    private static final String ELLIPSIS_TWO_DOTS = Resources.getSystem().getString(
-            R.string.ellipsis_two_dots);
 }
diff --git a/core/java/android/text/style/LocaleSpan.java b/core/java/android/text/style/LocaleSpan.java
new file mode 100644
index 0000000..a12c42f
--- /dev/null
+++ b/core/java/android/text/style/LocaleSpan.java
@@ -0,0 +1,84 @@
+/*
+ * 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.text.style;
+
+import android.graphics.Paint;
+import android.os.Parcel;
+import android.text.ParcelableSpan;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import java.util.Locale;
+
+/**
+ * Changes the {@link Locale} of the text to which the span is attached.
+ */
+public class LocaleSpan extends MetricAffectingSpan implements ParcelableSpan {
+    private final Locale mLocale;
+
+    /**
+     * Creates a LocaleSpan.
+     * @param locale The {@link Locale} of the text to which the span is
+     * attached.
+     */
+    public LocaleSpan(Locale locale) {
+        mLocale = locale;
+    }
+
+    public LocaleSpan(Parcel src) {
+        mLocale = new Locale(src.readString(), src.readString(), src.readString());
+    }
+
+    @Override
+    public int getSpanTypeId() {
+        return TextUtils.LOCALE_SPAN;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mLocale.getLanguage());
+        dest.writeString(mLocale.getCountry());
+        dest.writeString(mLocale.getVariant());
+    }
+
+    /**
+     * Returns the {@link Locale}.
+     *
+     * @return The {@link Locale} for this span.
+     */
+    public Locale getLocale() {
+        return mLocale;
+    }
+
+    @Override
+    public void updateDrawState(TextPaint ds) {
+        apply(ds, mLocale);
+    }
+
+    @Override
+    public void updateMeasureState(TextPaint paint) {
+        apply(paint, mLocale);
+    }
+
+    private static void apply(Paint paint, Locale locale) {
+        paint.setTextLocale(locale);
+    }
+}
diff --git a/core/java/android/util/FloatMath.java b/core/java/android/util/FloatMath.java
index 1d4eda4..9556223 100644
--- a/core/java/android/util/FloatMath.java
+++ b/core/java/android/util/FloatMath.java
@@ -80,4 +80,24 @@
      * @return the exponential of value
      */
     public static native float exp(float value);
+
+    /**
+     * Returns the closest float approximation of the result of raising {@code
+     * x} to the power of {@code y}.
+     *
+     * @param x the base of the operation.
+     * @param y the exponent of the operation.
+     * @return {@code x} to the power of {@code y}.
+     */
+    public static native float pow(float x, float y);
+
+    /**
+     * Returns {@code sqrt(}<i>{@code x}</i><sup>{@code 2}</sup>{@code +} <i>
+     * {@code y}</i><sup>{@code 2}</sup>{@code )}.
+     *
+     * @param x a float number
+     * @param y a float number
+     * @return the hypotenuse
+     */
+    public static native float hypot(float x, float y);
 }
diff --git a/core/java/android/util/Spline.java b/core/java/android/util/Spline.java
new file mode 100644
index 0000000..ed027eb
--- /dev/null
+++ b/core/java/android/util/Spline.java
@@ -0,0 +1,156 @@
+/*
+ * 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;
+
+/**
+ * Performs spline interpolation given a set of control points.
+ * @hide
+ */
+public final class Spline {
+    private final float[] mX;
+    private final float[] mY;
+    private final float[] mM;
+
+    private Spline(float[] x, float[] y, float[] m) {
+        mX = x;
+        mY = y;
+        mM = m;
+    }
+
+    /**
+     * Creates a monotone cubic spline from a given set of control points.
+     *
+     * The spline is guaranteed to pass through each control point exactly.
+     * Moreover, assuming the control points are monotonic (Y is non-decreasing or
+     * non-increasing) then the interpolated values will also be monotonic.
+     *
+     * This function uses the Fritsch-Carlson method for computing the spline parameters.
+     * http://en.wikipedia.org/wiki/Monotone_cubic_interpolation
+     *
+     * @param x The X component of the control points, strictly increasing.
+     * @param y The Y component of the control points, monotonic.
+     * @return
+     *
+     * @throws IllegalArgumentException if the X or Y arrays are null, have
+     * different lengths or have fewer than 2 values.
+     * @throws IllegalArgumentException if the control points are not monotonic.
+     */
+    public static Spline createMonotoneCubicSpline(float[] x, float[] y) {
+        if (x == null || y == null || x.length != y.length || x.length < 2) {
+            throw new IllegalArgumentException("There must be at least two control "
+                    + "points and the arrays must be of equal length.");
+        }
+
+        final int n = x.length;
+        float[] d = new float[n - 1]; // could optimize this out
+        float[] m = new float[n];
+
+        // Compute slopes of secant lines between successive points.
+        for (int i = 0; i < n - 1; i++) {
+            float h = x[i + 1] - x[i];
+            if (h <= 0f) {
+                throw new IllegalArgumentException("The control points must all "
+                        + "have strictly increasing X values.");
+            }
+            d[i] = (y[i + 1] - y[i]) / h;
+        }
+
+        // Initialize the tangents as the average of the secants.
+        m[0] = d[0];
+        for (int i = 1; i < n - 1; i++) {
+            m[i] = (d[i - 1] + d[i]) * 0.5f;
+        }
+        m[n - 1] = d[n - 2];
+
+        // Update the tangents to preserve monotonicity.
+        for (int i = 0; i < n - 1; i++) {
+            if (d[i] == 0f) { // successive Y values are equal
+                m[i] = 0f;
+                m[i + 1] = 0f;
+            } else {
+                float a = m[i] / d[i];
+                float b = m[i + 1] / d[i];
+                if (a < 0f || b < 0f) {
+                    throw new IllegalArgumentException("The control points must have "
+                            + "monotonic Y values.");
+                }
+                float h = FloatMath.hypot(a, b);
+                if (h > 9f) {
+                    float t = 3f / h;
+                    m[i] = t * a * d[i];
+                    m[i + 1] = t * b * d[i];
+                }
+            }
+        }
+        return new Spline(x, y, m);
+    }
+
+    /**
+     * Interpolates the value of Y = f(X) for given X.
+     * Clamps X to the domain of the spline.
+     *
+     * @param x The X value.
+     * @return The interpolated Y = f(X) value.
+     */
+    public float interpolate(float x) {
+        // Handle the boundary cases.
+        final int n = mX.length;
+        if (Float.isNaN(x)) {
+            return x;
+        }
+        if (x <= mX[0]) {
+            return mY[0];
+        }
+        if (x >= mX[n - 1]) {
+            return mY[n - 1];
+        }
+
+        // Find the index 'i' of the last point with smaller X.
+        // We know this will be within the spline due to the boundary tests.
+        int i = 0;
+        while (x >= mX[i + 1]) {
+            i += 1;
+            if (x == mX[i]) {
+                return mY[i];
+            }
+        }
+
+        // Perform cubic Hermite spline interpolation.
+        float h = mX[i + 1] - mX[i];
+        float t = (x - mX[i]) / h;
+        return (mY[i] * (1 + 2 * t) + h * mM[i] * t) * (1 - t) * (1 - t)
+                + (mY[i + 1] * (3 - 2 * t) + h * mM[i + 1] * (t - 1)) * t * t;
+    }
+
+    // For debugging.
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        final int n = mX.length;
+        str.append("[");
+        for (int i = 0; i < n; i++) {
+            if (i != 0) {
+                str.append(", ");
+            }
+            str.append("(").append(mX[i]);
+            str.append(", ").append(mY[i]);
+            str.append(": ").append(mM[i]).append(")");
+        }
+        str.append("]");
+        return str.toString();
+    }
+}
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 7d33ff4a..5a4f322 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -18,6 +18,7 @@
 
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
+import android.os.SystemClock;
 import android.text.format.DateUtils;
 
 import com.android.internal.util.XmlUtils;
@@ -391,6 +392,18 @@
         formatDuration(time-now, pw, 0);
     }
 
+    /** @hide Just for debugging; not internationalized. */
+    public static String formatUptime(long time) {
+        final long diff = time - SystemClock.uptimeMillis();
+        if (diff > 0) {
+            return time + " (in " + diff + " ms)";
+        }
+        if (diff < 0) {
+            return time + " (" + -diff + " ms ago)";
+        }
+        return time + " (now)";
+    }
+
     /**
      * Convert a System.currentTimeMillis() value to a time of day value like
      * that printed in logs. MM-DD HH:MM:SS.MMM
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 6288ce5..392d1f2 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.hardware.display.DisplayManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -165,7 +166,7 @@
         mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
         mLastFrameTimeNanos = Long.MIN_VALUE;
 
-        Display d = WindowManagerImpl.getDefault().getDefaultDisplay();
+        Display d = DisplayManager.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
         mFrameIntervalNanos = (long)(1000000000 / d.getRefreshRate());
 
         mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java
index 626f385..6c733f9 100644
--- a/core/java/android/view/ContextThemeWrapper.java
+++ b/core/java/android/view/ContextThemeWrapper.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.Build;
 
@@ -30,6 +31,8 @@
     private int mThemeResource;
     private Resources.Theme mTheme;
     private LayoutInflater mInflater;
+    private Configuration mOverrideConfiguration;
+    private Resources mResources;
 
     public ContextThemeWrapper() {
         super(null);
@@ -45,6 +48,41 @@
         super.attachBaseContext(newBase);
         mBase = newBase;
     }
+
+    /**
+     * Call to set an "override configuration" on this context -- this is
+     * a configuration that replies one or more values of the standard
+     * configuration that is applied to the context.  See
+     * {@link Context#createConfigurationContext(Configuration)} for more
+     * information.
+     *
+     * <p>This method can only be called once, and must be called before any
+     * calls to {@link #getResources()} are made.
+     */
+    public void applyOverrideConfiguration(Configuration overrideConfiguration) {
+        if (mResources != null) {
+            throw new IllegalStateException("getResources() has already been called");
+        }
+        if (mOverrideConfiguration != null) {
+            throw new IllegalStateException("Override configuration has already been set");
+        }
+        mOverrideConfiguration = new Configuration(overrideConfiguration);
+    }
+
+    @Override
+    public Resources getResources() {
+        if (mResources != null) {
+            return mResources;
+        }
+        if (mOverrideConfiguration == null) {
+            mResources = super.getResources();
+            return mResources;
+        } else {
+            Context resc = createConfigurationContext(mOverrideConfiguration);
+            mResources = resc.getResources();
+            return mResources;
+        }
+    }
     
     @Override public void setTheme(int resid) {
         mThemeResource = resid;
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 5409b38..6f8ca13 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -67,20 +67,16 @@
     private int mCachedAppHeightCompat;
 
     /**
-     * The default Display id.
+     * The default Display id, which is the id of the built-in primary display
+     * assuming there is one.
      */
     public static final int DEFAULT_DISPLAY = 0;
 
     /**
-     * Uninitialized display.
-     * @hide
-     */
-    public static final int NO_DISPLAY = -1;
-
-    /**
      * Internal method to create a display.
      * Applications should use {@link android.view.WindowManager#getDefaultDisplay()}
-     * to get a display object for the default display.
+     * or {@link android.hardware.display.DisplayManager#getDisplay}
+     * to get a display object.
      *
      * @hide
      */
@@ -114,6 +110,31 @@
     }
 
     /**
+     * Gets the display's layer stack.
+     *
+     * Each display has its own independent layer stack upon which surfaces
+     * are placed to be managed by surface flinger.
+     *
+     * @return The layer stack number.
+     * @hide
+     */
+    public int getLayerStack() {
+        // Note: This is the current convention but there is no requirement that
+        // the display id and layer stack id be the same.
+        return mDisplayId;
+    }
+
+    /**
+     * Gets the compatibility info used by this display instance.
+     *
+     * @return The compatibility info holder, or null if none is required.
+     * @hide
+     */
+    public CompatibilityInfoHolder getCompatibilityInfo() {
+        return mCompatibilityInfo;
+    }
+
+    /**
      * Gets the size of the display, in pixels.
      * <p>
      * Note that this value should <em>not</em> be used for computing layouts,
@@ -361,5 +382,16 @@
             mLastCachedAppSizeUpdate = now;
         }
     }
+
+    // For debugging purposes
+    @Override
+    public String toString() {
+        synchronized (this) {
+            updateDisplayInfoLocked();
+            mDisplayInfo.getAppMetrics(mTempMetrics, mCompatibilityInfo);
+            return "Display id " + mDisplayId + ": " + mDisplayInfo
+                    + ", " + mTempMetrics;
+        }
+    }
 }
 
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index c65ce63..e38f245 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -223,4 +223,17 @@
             }
         }
     }
+
+    // For debugging purposes
+    @Override
+    public String toString() {
+        return "app " + appWidth + " x " + appHeight
+                + ", real " + logicalWidth + " x " + logicalHeight
+                + ", largest app " + largestNominalAppWidth + " x " + largestNominalAppHeight
+                + ", smallest app " + smallestNominalAppWidth + " x " + smallestNominalAppHeight
+                + ", " + refreshRate + " fps"
+                + ", rotation " + rotation
+                + ", density " + logicalDensityDpi
+                + ", " + physicalXDpi + " x " + physicalYDpi + " dpi";
+    }
 }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 188fede..f906e24 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -1101,7 +1101,7 @@
                 attachInfo.mIgnoreDirtyState = true;
                 attachInfo.mDrawingTime = SystemClock.uptimeMillis();
 
-                view.mPrivateFlags |= View.DRAWN;
+                view.mPrivateFlags |= View.PFLAG_DRAWN;
 
                 final int surfaceState = checkCurrent();
                 if (surfaceState != SURFACE_STATE_ERROR) {
@@ -1135,9 +1135,9 @@
                     callbacks.onHardwarePreDraw(canvas);
 
                     try {
-                        view.mRecreateDisplayList =
-                                (view.mPrivateFlags & View.INVALIDATED) == View.INVALIDATED;
-                        view.mPrivateFlags &= ~View.INVALIDATED;
+                        view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
+                                == View.PFLAG_INVALIDATED;
+                        view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
 
                         long getDisplayListStartTime = 0;
                         if (mProfileEnabled) {
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 5bccdd4..7f2de50 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -84,7 +84,7 @@
     void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
             int startHeight);
     void overridePendingAppTransitionThumb(in Bitmap srcThumb, int startX, int startY,
-            IRemoteCallback startedCallback, boolean delayed);
+            IRemoteCallback startedCallback, boolean scaleUp);
     void executeAppTransition();
     void setAppStartingWindow(IBinder token, String pkg, int theme,
             in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index e93e480..c5d9255 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -59,8 +59,8 @@
      * @param requestedWidth The width the window wants to be.
      * @param requestedHeight The height the window wants to be.
      * @param viewVisibility Window root view's visibility.
-     * @param flags Request flags: {@link WindowManagerImpl#RELAYOUT_INSETS_PENDING},
-     * {@link WindowManagerImpl#RELAYOUT_DEFER_SURFACE_DESTROY}.
+     * @param flags Request flags: {@link WindowManagerGlobal#RELAYOUT_INSETS_PENDING},
+     * {@link WindowManagerGlobal#RELAYOUT_DEFER_SURFACE_DESTROY}.
      * @param outFrame Rect in which is placed the new position/size on
      * screen.
      * @param outContentInsets Rect in which is placed the offsets from
@@ -79,8 +79,8 @@
      * was last displayed.
      * @param outSurface Object in which is placed the new display surface.
      * 
-     * @return int Result flags: {@link WindowManagerImpl#RELAYOUT_SHOW_FOCUS},
-     * {@link WindowManagerImpl#RELAYOUT_FIRST_TIME}.
+     * @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_SHOW_FOCUS},
+     * {@link WindowManagerGlobal#RELAYOUT_FIRST_TIME}.
      */
     int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs,
             int requestedWidth, int requestedHeight, int viewVisibility,
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 5f5d1f2..517b514 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -246,22 +246,9 @@
     native private static void nativeClassInit();
     static { nativeClassInit(); }
 
-    /** create a surface @hide */
-    public Surface(SurfaceSession s,
-            int pid, int displayId, int w, int h, int format, int flags)
-        throws OutOfResourcesException {
-        checkHeadless();
-
-        if (DEBUG_RELEASE) {
-            mCreationStack = new Exception();
-        }
-        mCanvas = new CompatibleCanvas();
-        init(s,pid,null,displayId,w,h,format,flags);
-    }
-
     /** create a surface with a name @hide */
     public Surface(SurfaceSession s,
-            int pid, String name, int displayId, int w, int h, int format, int flags)
+            int pid, String name, int layerStack, int w, int h, int format, int flags)
         throws OutOfResourcesException {
         checkHeadless();
 
@@ -269,7 +256,7 @@
             mCreationStack = new Exception();
         }
         mCanvas = new CompatibleCanvas();
-        init(s,pid,name,displayId,w,h,format,flags);
+        init(s, pid, name, layerStack, w, h, format, flags);
         mName = name;
     }
 
@@ -470,7 +457,7 @@
     /** @hide */
     public native   void setWindowCrop(Rect crop);
     /** @hide */
-    public native   void setDisplayId(int displayId);
+    public native   void setLayerStack(int layerStack);
 
 
    
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index f4d40cb..fdf1c22 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -296,7 +296,7 @@
         }
         
         boolean opaque = true;
-        if ((mPrivateFlags & SKIP_DRAW) == 0) {
+        if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
             // this view draws, remove it from the transparent region
             opaque = super.gatherTransparentRegion(region);
         } else if (region != null) {
@@ -320,7 +320,7 @@
     public void draw(Canvas canvas) {
         if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
             // draw() is not called when SKIP_DRAW is set
-            if ((mPrivateFlags & SKIP_DRAW) == 0) {
+            if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
                 // punch a whole in the view-hierarchy below us
                 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
             }
@@ -332,7 +332,7 @@
     protected void dispatchDraw(Canvas canvas) {
         if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
             // if SKIP_DRAW is cleared, draw() has already punched a hole
-            if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
+            if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                 // punch a whole in the view-hierarchy below us
                 canvas.drawColor(0, PorterDuff.Mode.CLEAR);
             }
@@ -480,10 +480,10 @@
                     relayoutResult = mSession.relayout(
                         mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,
                             visible ? VISIBLE : GONE,
-                            WindowManagerImpl.RELAYOUT_DEFER_SURFACE_DESTROY,
+                            WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
                             mWinFrame, mContentInsets,
                             mVisibleInsets, mConfiguration, mNewSurface);
-                    if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) {
+                    if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
                         mReportDrawNeeded = true;
                     }
 
@@ -516,8 +516,8 @@
 
                     SurfaceHolder.Callback callbacks[] = null;
 
-                    final boolean surfaceChanged =
-                            (relayoutResult&WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED) != 0;
+                    final boolean surfaceChanged = (relayoutResult
+                            & WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED) != 0;
                     if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
                         mSurfaceCreated = false;
                         if (mSurface.isValid()) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 59aeffcf..b1f5e9e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -39,6 +39,7 @@
 import android.graphics.Shader;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -1568,17 +1569,17 @@
 
     // for mPrivateFlags:
     /** {@hide} */
-    static final int WANTS_FOCUS                    = 0x00000001;
+    static final int PFLAG_WANTS_FOCUS                 = 0x00000001;
     /** {@hide} */
-    static final int FOCUSED                        = 0x00000002;
+    static final int PFLAG_FOCUSED                     = 0x00000002;
     /** {@hide} */
-    static final int SELECTED                       = 0x00000004;
+    static final int PFLAG_SELECTED                    = 0x00000004;
     /** {@hide} */
-    static final int IS_ROOT_NAMESPACE              = 0x00000008;
+    static final int PFLAG_IS_ROOT_NAMESPACE           = 0x00000008;
     /** {@hide} */
-    static final int HAS_BOUNDS                     = 0x00000010;
+    static final int PFLAG_HAS_BOUNDS                  = 0x00000010;
     /** {@hide} */
-    static final int DRAWN                          = 0x00000020;
+    static final int PFLAG_DRAWN                       = 0x00000020;
     /**
      * When this flag is set, this view is running an animation on behalf of its
      * children and should therefore not cancel invalidate requests, even if they
@@ -1586,58 +1587,58 @@
      *
      * {@hide}
      */
-    static final int DRAW_ANIMATION                 = 0x00000040;
+    static final int PFLAG_DRAW_ANIMATION              = 0x00000040;
     /** {@hide} */
-    static final int SKIP_DRAW                      = 0x00000080;
+    static final int PFLAG_SKIP_DRAW                   = 0x00000080;
     /** {@hide} */
-    static final int ONLY_DRAWS_BACKGROUND          = 0x00000100;
+    static final int PFLAG_ONLY_DRAWS_BACKGROUND       = 0x00000100;
     /** {@hide} */
-    static final int REQUEST_TRANSPARENT_REGIONS    = 0x00000200;
+    static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200;
     /** {@hide} */
-    static final int DRAWABLE_STATE_DIRTY           = 0x00000400;
+    static final int PFLAG_DRAWABLE_STATE_DIRTY        = 0x00000400;
     /** {@hide} */
-    static final int MEASURED_DIMENSION_SET         = 0x00000800;
+    static final int PFLAG_MEASURED_DIMENSION_SET      = 0x00000800;
     /** {@hide} */
-    static final int FORCE_LAYOUT                   = 0x00001000;
+    static final int PFLAG_FORCE_LAYOUT                = 0x00001000;
     /** {@hide} */
-    static final int LAYOUT_REQUIRED                = 0x00002000;
+    static final int PFLAG_LAYOUT_REQUIRED             = 0x00002000;
 
-    private static final int PRESSED                = 0x00004000;
+    private static final int PFLAG_PRESSED             = 0x00004000;
 
     /** {@hide} */
-    static final int DRAWING_CACHE_VALID            = 0x00008000;
+    static final int PFLAG_DRAWING_CACHE_VALID         = 0x00008000;
     /**
      * Flag used to indicate that this view should be drawn once more (and only once
      * more) after its animation has completed.
      * {@hide}
      */
-    static final int ANIMATION_STARTED              = 0x00010000;
+    static final int PFLAG_ANIMATION_STARTED           = 0x00010000;
 
-    private static final int SAVE_STATE_CALLED      = 0x00020000;
+    private static final int PFLAG_SAVE_STATE_CALLED   = 0x00020000;
 
     /**
      * Indicates that the View returned true when onSetAlpha() was called and that
      * the alpha must be restored.
      * {@hide}
      */
-    static final int ALPHA_SET                      = 0x00040000;
+    static final int PFLAG_ALPHA_SET                   = 0x00040000;
 
     /**
      * Set by {@link #setScrollContainer(boolean)}.
      */
-    static final int SCROLL_CONTAINER               = 0x00080000;
+    static final int PFLAG_SCROLL_CONTAINER            = 0x00080000;
 
     /**
      * Set by {@link #setScrollContainer(boolean)}.
      */
-    static final int SCROLL_CONTAINER_ADDED         = 0x00100000;
+    static final int PFLAG_SCROLL_CONTAINER_ADDED      = 0x00100000;
 
     /**
      * View flag indicating whether this view was invalidated (fully or partially.)
      *
      * @hide
      */
-    static final int DIRTY                          = 0x00200000;
+    static final int PFLAG_DIRTY                       = 0x00200000;
 
     /**
      * View flag indicating whether this view was invalidated by an opaque
@@ -1645,35 +1646,35 @@
      *
      * @hide
      */
-    static final int DIRTY_OPAQUE                   = 0x00400000;
+    static final int PFLAG_DIRTY_OPAQUE                = 0x00400000;
 
     /**
-     * Mask for {@link #DIRTY} and {@link #DIRTY_OPAQUE}.
+     * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}.
      *
      * @hide
      */
-    static final int DIRTY_MASK                     = 0x00600000;
+    static final int PFLAG_DIRTY_MASK                  = 0x00600000;
 
     /**
      * Indicates whether the background is opaque.
      *
      * @hide
      */
-    static final int OPAQUE_BACKGROUND              = 0x00800000;
+    static final int PFLAG_OPAQUE_BACKGROUND           = 0x00800000;
 
     /**
      * Indicates whether the scrollbars are opaque.
      *
      * @hide
      */
-    static final int OPAQUE_SCROLLBARS              = 0x01000000;
+    static final int PFLAG_OPAQUE_SCROLLBARS           = 0x01000000;
 
     /**
      * Indicates whether the view is opaque.
      *
      * @hide
      */
-    static final int OPAQUE_MASK                    = 0x01800000;
+    static final int PFLAG_OPAQUE_MASK                 = 0x01800000;
 
     /**
      * Indicates a prepressed state;
@@ -1683,27 +1684,27 @@
      *
      * @hide
      */
-    private static final int PREPRESSED             = 0x02000000;
+    private static final int PFLAG_PREPRESSED          = 0x02000000;
 
     /**
      * Indicates whether the view is temporarily detached.
      *
      * @hide
      */
-    static final int CANCEL_NEXT_UP_EVENT = 0x04000000;
+    static final int PFLAG_CANCEL_NEXT_UP_EVENT        = 0x04000000;
 
     /**
      * Indicates that we should awaken scroll bars once attached
      *
      * @hide
      */
-    private static final int AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000;
+    private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000;
 
     /**
      * Indicates that the view has received HOVER_ENTER.  Cleared on HOVER_EXIT.
      * @hide
      */
-    private static final int HOVERED              = 0x10000000;
+    private static final int PFLAG_HOVERED             = 0x10000000;
 
     /**
      * Indicates that pivotX or pivotY were explicitly set and we should not assume the center
@@ -1711,10 +1712,10 @@
      *
      * @hide
      */
-    private static final int PIVOT_EXPLICITLY_SET = 0x20000000;
+    private static final int PFLAG_PIVOT_EXPLICITLY_SET = 0x20000000;
 
     /** {@hide} */
-    static final int ACTIVATED                    = 0x40000000;
+    static final int PFLAG_ACTIVATED                   = 0x40000000;
 
     /**
      * Indicates that this view was specifically invalidated, not just dirtied because some
@@ -1724,7 +1725,7 @@
      *
      * @hide
      */
-    static final int INVALIDATED                  = 0x80000000;
+    static final int PFLAG_INVALIDATED                 = 0x80000000;
 
     /* Masks for mPrivateFlags2 */
 
@@ -1733,7 +1734,7 @@
      * Cleared when the drag operation concludes.
      * @hide
      */
-    static final int DRAG_CAN_ACCEPT              = 0x00000001;
+    static final int PFLAG2_DRAG_CAN_ACCEPT            = 0x00000001;
 
     /**
      * Indicates that this view is currently directly under the drag location in a
@@ -1741,7 +1742,7 @@
      * the drag exits the view, or when the drag operation concludes.
      * @hide
      */
-    static final int DRAG_HOVERED                 = 0x00000002;
+    static final int PFLAG2_DRAG_HOVERED               = 0x00000002;
 
     /**
      * Horizontal layout direction of this view is from Left to Right.
@@ -1771,32 +1772,33 @@
      * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED)
      * @hide
      */
-    static final int LAYOUT_DIRECTION_MASK_SHIFT = 2;
+    static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2;
 
     /**
      * Mask for use with private flags indicating bits used for horizontal layout direction.
      * @hide
      */
-    static final int LAYOUT_DIRECTION_MASK = 0x00000003 << LAYOUT_DIRECTION_MASK_SHIFT;
+    static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT;
 
     /**
      * Indicates whether the view horizontal layout direction has been resolved and drawn to the
      * right-to-left direction.
      * @hide
      */
-    static final int LAYOUT_DIRECTION_RESOLVED_RTL = 4 << LAYOUT_DIRECTION_MASK_SHIFT;
+    static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT;
 
     /**
      * Indicates whether the view horizontal layout direction has been resolved.
      * @hide
      */
-    static final int LAYOUT_DIRECTION_RESOLVED = 8 << LAYOUT_DIRECTION_MASK_SHIFT;
+    static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT;
 
     /**
      * Mask for use with private flags indicating bits used for resolved horizontal layout direction.
      * @hide
      */
-    static final int LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C << LAYOUT_DIRECTION_MASK_SHIFT;
+    static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C
+            << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT;
 
     /*
      * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct
@@ -1823,7 +1825,7 @@
      *
      * @hide
      */
-    static final int HAS_TRANSIENT_STATE = 0x00000100;
+    static final int PFLAG2_HAS_TRANSIENT_STATE = 0x00000100;
 
 
     /**
@@ -1863,58 +1865,61 @@
     /**
      * Default text direction is inherited
      */
-    protected static int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT;
+    public static int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT;
 
     /**
      * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED)
      * @hide
      */
-    static final int TEXT_DIRECTION_MASK_SHIFT = 6;
+    static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6;
 
     /**
      * Mask for use with private flags indicating bits used for text direction.
      * @hide
      */
-    static final int TEXT_DIRECTION_MASK = 0x00000007 << TEXT_DIRECTION_MASK_SHIFT;
+    static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007
+            << PFLAG2_TEXT_DIRECTION_MASK_SHIFT;
 
     /**
      * Array of text direction flags for mapping attribute "textDirection" to correct
      * flag value.
      * @hide
      */
-    private static final int[] TEXT_DIRECTION_FLAGS = {
-            TEXT_DIRECTION_INHERIT << TEXT_DIRECTION_MASK_SHIFT,
-            TEXT_DIRECTION_FIRST_STRONG << TEXT_DIRECTION_MASK_SHIFT,
-            TEXT_DIRECTION_ANY_RTL << TEXT_DIRECTION_MASK_SHIFT,
-            TEXT_DIRECTION_LTR << TEXT_DIRECTION_MASK_SHIFT,
-            TEXT_DIRECTION_RTL << TEXT_DIRECTION_MASK_SHIFT,
-            TEXT_DIRECTION_LOCALE << TEXT_DIRECTION_MASK_SHIFT
+    private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = {
+            TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
+            TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
+            TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
+            TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
+            TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
+            TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT
     };
 
     /**
      * Indicates whether the view text direction has been resolved.
      * @hide
      */
-    static final int TEXT_DIRECTION_RESOLVED = 0x00000008 << TEXT_DIRECTION_MASK_SHIFT;
+    static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008
+            << PFLAG2_TEXT_DIRECTION_MASK_SHIFT;
 
     /**
      * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED)
      * @hide
      */
-    static final int TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10;
+    static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10;
 
     /**
      * Mask for use with private flags indicating bits used for resolved text direction.
      * @hide
      */
-    static final int TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 << TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
+    static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007
+            << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
 
     /**
      * Indicates whether the view text direction has been resolved to the "first strong" heuristic.
      * @hide
      */
-    static final int TEXT_DIRECTION_RESOLVED_DEFAULT =
-            TEXT_DIRECTION_FIRST_STRONG << TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
+    static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT =
+            TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
 
     /*
      * Default text alignment. The text alignment of this View is inherited from its parent.
@@ -1970,58 +1975,59 @@
     /**
      * Default text alignment is inherited
      */
-    protected static int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY;
+    public static int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY;
 
     /**
       * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED)
       * @hide
       */
-    static final int TEXT_ALIGNMENT_MASK_SHIFT = 13;
+    static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13;
 
     /**
       * Mask for use with private flags indicating bits used for text alignment.
       * @hide
       */
-    static final int TEXT_ALIGNMENT_MASK = 0x00000007 << TEXT_ALIGNMENT_MASK_SHIFT;
+    static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT;
 
     /**
      * Array of text direction flags for mapping attribute "textAlignment" to correct
      * flag value.
      * @hide
      */
-    private static final int[] TEXT_ALIGNMENT_FLAGS = {
-            TEXT_ALIGNMENT_INHERIT << TEXT_ALIGNMENT_MASK_SHIFT,
-            TEXT_ALIGNMENT_GRAVITY << TEXT_ALIGNMENT_MASK_SHIFT,
-            TEXT_ALIGNMENT_TEXT_START << TEXT_ALIGNMENT_MASK_SHIFT,
-            TEXT_ALIGNMENT_TEXT_END << TEXT_ALIGNMENT_MASK_SHIFT,
-            TEXT_ALIGNMENT_CENTER << TEXT_ALIGNMENT_MASK_SHIFT,
-            TEXT_ALIGNMENT_VIEW_START << TEXT_ALIGNMENT_MASK_SHIFT,
-            TEXT_ALIGNMENT_VIEW_END << TEXT_ALIGNMENT_MASK_SHIFT
+    private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = {
+            TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT,
+            TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT,
+            TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT,
+            TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT,
+            TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT,
+            TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT,
+            TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT
     };
 
     /**
      * Indicates whether the view text alignment has been resolved.
      * @hide
      */
-    static final int TEXT_ALIGNMENT_RESOLVED = 0x00000008 << TEXT_ALIGNMENT_MASK_SHIFT;
+    static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT;
 
     /**
      * Bit shift to get the resolved text alignment.
      * @hide
      */
-    static final int TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17;
+    static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17;
 
     /**
      * Mask for use with private flags indicating bits used for text alignment.
      * @hide
      */
-    static final int TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 << TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
+    static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007
+            << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
 
     /**
      * Indicates whether if the view text alignment has been resolved to gravity
      */
-    public static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT =
-            TEXT_ALIGNMENT_GRAVITY << TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
+    private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT =
+            TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
 
     // Accessiblity constants for mPrivateFlags2
 
@@ -2029,7 +2035,7 @@
      * Shift for the bits in {@link #mPrivateFlags2} related to the
      * "importantForAccessibility" attribute.
      */
-    static final int IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20;
+    static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20;
 
     /**
      * Automatically determine whether a view is important for accessibility.
@@ -2055,26 +2061,27 @@
      * Mask for obtainig the bits which specify how to determine
      * whether a view is important for accessibility.
      */
-    static final int IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO
+    static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO
         | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO)
-        << IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
+        << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
 
     /**
      * Flag indicating whether a view has accessibility focus.
      */
-    static final int ACCESSIBILITY_FOCUSED = 0x00000040 << IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
+    static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x00000040 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
 
     /**
      * Flag indicating whether a view state for accessibility has changed.
      */
-    static final int ACCESSIBILITY_STATE_CHANGED = 0x00000080 << IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
+    static final int PFLAG2_ACCESSIBILITY_STATE_CHANGED = 0x00000080
+            << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
 
     /**
      * Flag indicating whether a view failed the quickReject() check in draw(). This condition
      * is used to check whether later changes to the view's transform should invalidate the
      * view to force the quickReject test to run again.
      */
-    static final int VIEW_QUICK_REJECTED = 0x10000000;
+    static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000;
 
     /**
      * Flag indicating that start/end padding has been resolved into left/right padding
@@ -2083,7 +2090,7 @@
      * during measurement. In some special cases this is required such as when an adapter-based
      * view measures prospective children without attaching them to a window.
      */
-    static final int PADDING_RESOLVED = 0x20000000;
+    static final int PFLAG2_PADDING_RESOLVED = 0x20000000;
 
     // There are a couple of flags left in mPrivateFlags2
 
@@ -2096,19 +2103,19 @@
      * an animation is cleared between successive frames, in order to tell the associated
      * DisplayList to clear its animation matrix.
      */
-    static final int VIEW_IS_ANIMATING_TRANSFORM = 0x1;
+    static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1;
 
     /**
      * Flag indicating that view has an alpha animation set on it. This is used to track whether an
      * animation is cleared between successive frames, in order to tell the associated
      * DisplayList to restore its alpha value.
      */
-    static final int VIEW_IS_ANIMATING_ALPHA = 0x2;
+    static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2;
 
 
     /* End of masks for mPrivateFlags3 */
 
-    static final int DRAG_MASK = DRAG_CAN_ACCEPT | DRAG_HOVERED;
+    static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
 
     /**
      * Always allow a user to over-scroll this view, provided it is a
@@ -2475,16 +2482,16 @@
      * {@hide}
      */
     @ViewDebug.ExportedProperty(flagMapping = {
-        @ViewDebug.FlagToString(mask = FORCE_LAYOUT, equals = FORCE_LAYOUT,
+        @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT,
                 name = "FORCE_LAYOUT"),
-        @ViewDebug.FlagToString(mask = LAYOUT_REQUIRED, equals = LAYOUT_REQUIRED,
+        @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED,
                 name = "LAYOUT_REQUIRED"),
-        @ViewDebug.FlagToString(mask = DRAWING_CACHE_VALID, equals = DRAWING_CACHE_VALID,
+        @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID,
             name = "DRAWING_CACHE_INVALID", outputIf = false),
-        @ViewDebug.FlagToString(mask = DRAWN, equals = DRAWN, name = "DRAWN", outputIf = true),
-        @ViewDebug.FlagToString(mask = DRAWN, equals = DRAWN, name = "NOT_DRAWN", outputIf = false),
-        @ViewDebug.FlagToString(mask = DIRTY_MASK, equals = DIRTY_OPAQUE, name = "DIRTY_OPAQUE"),
-        @ViewDebug.FlagToString(mask = DIRTY_MASK, equals = DIRTY, name = "DIRTY")
+        @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true),
+        @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false),
+        @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"),
+        @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY")
     })
     int mPrivateFlags;
     int mPrivateFlags2;
@@ -2790,6 +2797,20 @@
     int mUserPaddingEnd;
 
     /**
+     * Whether a left padding has been defined during layout inflation.
+     *
+     * @hide
+     */
+    boolean mUserPaddingLeftDefined = false;
+
+    /**
+     * Whether a right padding has been defined during layout inflation.
+     *
+     * @hide
+     */
+    boolean mUserPaddingRightDefined = false;
+
+    /**
      * Default undefined padding
      */
     private static final int UNDEFINED_PADDING = Integer.MIN_VALUE;
@@ -3086,6 +3107,19 @@
      */
     private boolean mSendingHoverAccessibilityEvents;
 
+    /**
+     * Delegate for injecting accessiblity functionality.
+     */
+    AccessibilityDelegate mAccessibilityDelegate;
+
+    /**
+     * Consistency verifier for debugging purposes.
+     * @hide
+     */
+    protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
+            InputEventConsistencyVerifier.isInstrumentationEnabled() ?
+                    new InputEventConsistencyVerifier(this, 0) : null;
+
     private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
 
     /**
@@ -3099,10 +3133,10 @@
         mResources = context != null ? context.getResources() : null;
         mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED;
         // Set layout and text direction defaults
-        mPrivateFlags2 = (LAYOUT_DIRECTION_DEFAULT << LAYOUT_DIRECTION_MASK_SHIFT) |
-                (TEXT_DIRECTION_DEFAULT << TEXT_DIRECTION_MASK_SHIFT) |
-                (TEXT_ALIGNMENT_DEFAULT << TEXT_ALIGNMENT_MASK_SHIFT) |
-                (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << IMPORTANT_FOR_ACCESSIBILITY_SHIFT);
+        mPrivateFlags2 = (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) |
+                (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) |
+                (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) |
+                (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT);
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS);
         mUserPaddingStart = UNDEFINED_PADDING;
@@ -3110,19 +3144,6 @@
     }
 
     /**
-     * Delegate for injecting accessiblity functionality.
-     */
-    AccessibilityDelegate mAccessibilityDelegate;
-
-    /**
-     * Consistency verifier for debugging purposes.
-     * @hide
-     */
-    protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
-            InputEventConsistencyVerifier.isInstrumentationEnabled() ?
-                    new InputEventConsistencyVerifier(this, 0) : null;
-
-    /**
      * Constructor that is called when inflating a view from XML. This is called
      * when a view is being constructed from an XML file, supplying attributes
      * that were specified in the XML file. This version uses a default style of
@@ -3195,8 +3216,11 @@
         boolean transformSet = false;
 
         int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY;
-
         int overScrollMode = mOverScrollMode;
+        boolean initializeScrollbars = false;
+
+        final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
+
         final int N = a.getIndexCount();
         for (int i = 0; i < N; i++) {
             int attr = a.getIndex(i);
@@ -3206,15 +3230,19 @@
                     break;
                 case com.android.internal.R.styleable.View_padding:
                     padding = a.getDimensionPixelSize(attr, -1);
+                    mUserPaddingLeftDefined = true;
+                    mUserPaddingRightDefined = true;
                     break;
                  case com.android.internal.R.styleable.View_paddingLeft:
                     leftPadding = a.getDimensionPixelSize(attr, -1);
+                    mUserPaddingLeftDefined = true;
                     break;
                 case com.android.internal.R.styleable.View_paddingTop:
                     topPadding = a.getDimensionPixelSize(attr, -1);
                     break;
                 case com.android.internal.R.styleable.View_paddingRight:
                     rightPadding = a.getDimensionPixelSize(attr, -1);
+                    mUserPaddingRightDefined = true;
                     break;
                 case com.android.internal.R.styleable.View_paddingBottom:
                     bottomPadding = a.getDimensionPixelSize(attr, -1);
@@ -3325,12 +3353,12 @@
                     break;
                 case com.android.internal.R.styleable.View_layoutDirection:
                     // Clear any layout direction flags (included resolved bits) already set
-                    mPrivateFlags2 &= ~(LAYOUT_DIRECTION_MASK | LAYOUT_DIRECTION_RESOLVED_MASK);
+                    mPrivateFlags2 &= ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK);
                     // Set the layout direction flags depending on the value of the attribute
                     final int layoutDirection = a.getInt(attr, -1);
                     final int value = (layoutDirection != -1) ?
                             LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT;
-                    mPrivateFlags2 |= (value << LAYOUT_DIRECTION_MASK_SHIFT);
+                    mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT);
                     break;
                 case com.android.internal.R.styleable.View_drawingCacheQuality:
                     final int cacheQuality = a.getInt(attr, 0);
@@ -3359,12 +3387,12 @@
                     if (scrollbars != SCROLLBARS_NONE) {
                         viewFlagValues |= scrollbars;
                         viewFlagMasks |= SCROLLBARS_MASK;
-                        initializeScrollbars(a);
+                        initializeScrollbars = true;
                     }
                     break;
                 //noinspection deprecation
                 case R.styleable.View_fadingEdge:
-                    if (context.getApplicationInfo().targetSdkVersion >= ICE_CREAM_SANDWICH) {
+                    if (targetSdkVersion >= ICE_CREAM_SANDWICH) {
                         // Ignore the attribute starting with ICS
                         break;
                     }
@@ -3475,19 +3503,19 @@
                     break;
                 case R.styleable.View_textDirection:
                     // Clear any text direction flag already set
-                    mPrivateFlags2 &= ~TEXT_DIRECTION_MASK;
+                    mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK;
                     // Set the text direction flags depending on the value of the attribute
                     final int textDirection = a.getInt(attr, -1);
                     if (textDirection != -1) {
-                        mPrivateFlags2 |= TEXT_DIRECTION_FLAGS[textDirection];
+                        mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection];
                     }
                     break;
                 case R.styleable.View_textAlignment:
                     // Clear any text alignment flag already set
-                    mPrivateFlags2 &= ~TEXT_ALIGNMENT_MASK;
+                    mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK;
                     // Set the text alignment flag depending on the value of the attribute
                     final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT);
-                    mPrivateFlags2 |= TEXT_ALIGNMENT_FLAGS[textAlignment];
+                    mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment];
                     break;
                 case R.styleable.View_importantForAccessibility:
                     setImportantForAccessibility(a.getInt(attr,
@@ -3496,12 +3524,11 @@
             }
         }
 
-        a.recycle();
-
         setOverScrollMode(overScrollMode);
 
-        // Cache user padding as we cannot fully resolve padding here (we dont have yet the resolved
-        // layout direction). Those cached values will be used later during padding resolution.
+        // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet
+        // the resolved layout direction). Those cached values will be used later during padding
+        // resolution.
         mUserPaddingStart = startPadding;
         mUserPaddingEnd = endPadding;
 
@@ -3529,6 +3556,12 @@
             setFlags(viewFlagValues, viewFlagMasks);
         }
 
+        if (initializeScrollbars) {
+            initializeScrollbars(a);
+        }
+
+        a.recycle();
+
         // Needs to be called after mViewFlags is set
         if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) {
             recomputePadding();
@@ -3562,6 +3595,81 @@
         mResources = null;
     }
 
+    public String toString() {
+        StringBuilder out = new StringBuilder(128);
+        out.append(getClass().getName());
+        out.append('{');
+        out.append(Integer.toHexString(System.identityHashCode(this)));
+        out.append(' ');
+        switch (mViewFlags&VISIBILITY_MASK) {
+            case VISIBLE: out.append('V'); break;
+            case INVISIBLE: out.append('I'); break;
+            case GONE: out.append('G'); break;
+            default: out.append('.'); break;
+        }
+        out.append((mViewFlags&FOCUSABLE_MASK) == FOCUSABLE ? 'F' : '.');
+        out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.');
+        out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D');
+        out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.');
+        out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.');
+        out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.');
+        out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.');
+        out.append(' ');
+        out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.');
+        out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.');
+        out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.');
+        if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) {
+            out.append('p');
+        } else {
+            out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.');
+        }
+        out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.');
+        out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.');
+        out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.');
+        out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.');
+        out.append(' ');
+        out.append(mLeft);
+        out.append(',');
+        out.append(mTop);
+        out.append('-');
+        out.append(mRight);
+        out.append(',');
+        out.append(mBottom);
+        final int id = getId();
+        if (id != NO_ID) {
+            out.append(" #");
+            out.append(Integer.toHexString(id));
+            final Resources r = mResources;
+            if (id != 0 && r != null) {
+                try {
+                    String pkgname;
+                    switch (id&0xff000000) {
+                        case 0x7f000000:
+                            pkgname="app";
+                            break;
+                        case 0x01000000:
+                            pkgname="android";
+                            break;
+                        default:
+                            pkgname = r.getResourcePackageName(id);
+                            break;
+                    }
+                    String typename = r.getResourceTypeName(id);
+                    String entryname = r.getResourceEntryName(id);
+                    out.append(" ");
+                    out.append(pkgname);
+                    out.append(":");
+                    out.append(typename);
+                    out.append("/");
+                    out.append(entryname);
+                } catch (Resources.NotFoundException e) {
+                }
+            }
+        }
+        out.append("}");
+        return out.toString();
+    }
+
     /**
      * <p>
      * Initializes the fading edges from a given set of styled attributes. This
@@ -4119,8 +4227,8 @@
             System.out.println(this + " requestFocus()");
         }
 
-        if ((mPrivateFlags & FOCUSED) == 0) {
-            mPrivateFlags |= FOCUSED;
+        if ((mPrivateFlags & PFLAG_FOCUSED) == 0) {
+            mPrivateFlags |= PFLAG_FOCUSED;
 
             if (mParent != null) {
                 mParent.requestChildFocus(this, this);
@@ -4204,8 +4312,8 @@
             System.out.println(this + " clearFocus()");
         }
 
-        if ((mPrivateFlags & FOCUSED) != 0) {
-            mPrivateFlags &= ~FOCUSED;
+        if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
+            mPrivateFlags &= ~PFLAG_FOCUSED;
 
             if (mParent != null) {
                 mParent.clearChildFocus(this);
@@ -4239,8 +4347,8 @@
             System.out.println(this + " unFocus()");
         }
 
-        if ((mPrivateFlags & FOCUSED) != 0) {
-            mPrivateFlags &= ~FOCUSED;
+        if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
+            mPrivateFlags &= ~PFLAG_FOCUSED;
 
             onFocusChanged(false, 0, null);
             refreshDrawableState();
@@ -4259,7 +4367,7 @@
      */
     @ViewDebug.ExportedProperty(category = "focus")
     public boolean hasFocus() {
-        return (mPrivateFlags & FOCUSED) != 0;
+        return (mPrivateFlags & PFLAG_FOCUSED) != 0;
     }
 
     /**
@@ -4959,7 +5067,7 @@
      */
     @ViewDebug.ExportedProperty(category = "focus")
     public boolean isFocused() {
-        return (mPrivateFlags & FOCUSED) != 0;
+        return (mPrivateFlags & PFLAG_FOCUSED) != 0;
     }
 
     /**
@@ -4970,7 +5078,7 @@
      *         be found.
      */
     public View findFocus() {
-        return (mPrivateFlags & FOCUSED) != 0 ? this : null;
+        return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null;
     }
 
     /**
@@ -4983,7 +5091,7 @@
      * @attr ref android.R.styleable#View_isScrollContainer
      */
     public boolean isScrollContainer() {
-        return (mPrivateFlags & SCROLL_CONTAINER_ADDED) != 0;
+        return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0;
     }
 
     /**
@@ -4997,16 +5105,16 @@
      */
     public void setScrollContainer(boolean isScrollContainer) {
         if (isScrollContainer) {
-            if (mAttachInfo != null && (mPrivateFlags&SCROLL_CONTAINER_ADDED) == 0) {
+            if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) {
                 mAttachInfo.mScrollContainers.add(this);
-                mPrivateFlags |= SCROLL_CONTAINER_ADDED;
+                mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED;
             }
-            mPrivateFlags |= SCROLL_CONTAINER;
+            mPrivateFlags |= PFLAG_SCROLL_CONTAINER;
         } else {
-            if ((mPrivateFlags&SCROLL_CONTAINER_ADDED) != 0) {
+            if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) {
                 mAttachInfo.mScrollContainers.remove(this);
             }
-            mPrivateFlags &= ~(SCROLL_CONTAINER|SCROLL_CONTAINER_ADDED);
+            mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED);
         }
     }
 
@@ -5513,7 +5621,7 @@
         @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE,  to = "LOCALE")
     })
     public int getLayoutDirection() {
-        return (mPrivateFlags2 & LAYOUT_DIRECTION_MASK) >> LAYOUT_DIRECTION_MASK_SHIFT;
+        return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT;
     }
 
     /**
@@ -5531,12 +5639,15 @@
     public void setLayoutDirection(int layoutDirection) {
         if (getLayoutDirection() != layoutDirection) {
             // Reset the current layout direction and the resolved one
-            mPrivateFlags2 &= ~LAYOUT_DIRECTION_MASK;
+            mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK;
             resetResolvedLayoutDirection();
-            // Set the new layout direction (filtered) and ask for a layout pass
+            // Reset padding resolution
+            mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED;
+            // Set the new layout direction (filtered)
             mPrivateFlags2 |=
-                    ((layoutDirection << LAYOUT_DIRECTION_MASK_SHIFT) & LAYOUT_DIRECTION_MASK);
-            resolvePadding();
+                    ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK);
+            resolveRtlProperties();
+            // ... and ask for a layout pass
             requestLayout();
         }
     }
@@ -5552,11 +5663,16 @@
         @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL")
     })
     public int getResolvedLayoutDirection() {
+        final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
+        if (targetSdkVersion < JELLY_BEAN_MR1) {
+            mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED;
+            return LAYOUT_DIRECTION_LTR;
+        }
         // The layout direction will be resolved only if needed
-        if ((mPrivateFlags2 & LAYOUT_DIRECTION_RESOLVED) != LAYOUT_DIRECTION_RESOLVED) {
+        if ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) != PFLAG2_LAYOUT_DIRECTION_RESOLVED) {
             resolveLayoutDirection();
         }
-        return ((mPrivateFlags2 & LAYOUT_DIRECTION_RESOLVED_RTL) == LAYOUT_DIRECTION_RESOLVED_RTL) ?
+        return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ?
                 LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR;
     }
 
@@ -5585,7 +5701,7 @@
      */
     @ViewDebug.ExportedProperty(category = "layout")
     public boolean hasTransientState() {
-        return (mPrivateFlags2 & HAS_TRANSIENT_STATE) == HAS_TRANSIENT_STATE;
+        return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE;
     }
 
     /**
@@ -5612,8 +5728,8 @@
         if ((hasTransientState && mTransientStateCount == 1) ||
                 (!hasTransientState && mTransientStateCount == 0)) {
             // update flag if we've just incremented up from 0 or decremented down to 0
-            mPrivateFlags2 = (mPrivateFlags2 & ~HAS_TRANSIENT_STATE) |
-                    (hasTransientState ? HAS_TRANSIENT_STATE : 0);
+            mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) |
+                    (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0);
             if (mParent != null) {
                 try {
                     mParent.childHasTransientStateChanged(this, hasTransientState);
@@ -5736,12 +5852,12 @@
      *        the View's internal state from a previously set "pressed" state.
      */
     public void setPressed(boolean pressed) {
-        final boolean needsRefresh = pressed != ((mPrivateFlags & PRESSED) == PRESSED);
+        final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED);
 
         if (pressed) {
-            mPrivateFlags |= PRESSED;
+            mPrivateFlags |= PFLAG_PRESSED;
         } else {
-            mPrivateFlags &= ~PRESSED;
+            mPrivateFlags &= ~PFLAG_PRESSED;
         }
 
         if (needsRefresh) {
@@ -5772,7 +5888,7 @@
      * @return true if the view is currently pressed, false otherwise
      */
     public boolean isPressed() {
-        return (mPrivateFlags & PRESSED) == PRESSED;
+        return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED;
     }
 
     /**
@@ -6099,7 +6215,7 @@
      * @return True if this View is accessibility focused.
      */
     boolean isAccessibilityFocused() {
-        return (mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0;
+        return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0;
     }
 
     /**
@@ -6124,8 +6240,8 @@
         if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
             return false;
         }
-        if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) == 0) {
-            mPrivateFlags2 |= ACCESSIBILITY_FOCUSED;
+        if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) {
+            mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED;
             ViewRootImpl viewRootImpl = getViewRootImpl();
             if (viewRootImpl != null) {
                 viewRootImpl.setAccessibilityFocus(this, null);
@@ -6147,8 +6263,8 @@
      * @hide
      */
     public void clearAccessibilityFocus() {
-        if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) {
-            mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED;
+        if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) {
+            mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED;
             invalidate();
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
             notifyAccessibilityStateChanged();
@@ -6196,8 +6312,8 @@
      * another view.
      */
     void clearAccessibilityFocusNoCallbacks() {
-        if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) {
-            mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED;
+        if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) {
+            mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED;
             invalidate();
         }
     }
@@ -6354,8 +6470,8 @@
             @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no")
         })
     public int getImportantForAccessibility() {
-        return (mPrivateFlags2 & IMPORTANT_FOR_ACCESSIBILITY_MASK)
-                >> IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
+        return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK)
+                >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
     }
 
     /**
@@ -6373,9 +6489,9 @@
      */
     public void setImportantForAccessibility(int mode) {
         if (mode != getImportantForAccessibility()) {
-            mPrivateFlags2 &= ~IMPORTANT_FOR_ACCESSIBILITY_MASK;
-            mPrivateFlags2 |= (mode << IMPORTANT_FOR_ACCESSIBILITY_SHIFT)
-                    & IMPORTANT_FOR_ACCESSIBILITY_MASK;
+            mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK;
+            mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT)
+                    & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK;
             notifyAccessibilityStateChanged();
         }
     }
@@ -6388,8 +6504,8 @@
      * @hide
      */
     public boolean isImportantForAccessibility() {
-        final int mode = (mPrivateFlags2 & IMPORTANT_FOR_ACCESSIBILITY_MASK)
-                >> IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
+        final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK)
+                >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT;
         switch (mode) {
             case IMPORTANT_FOR_ACCESSIBILITY_YES:
                 return true;
@@ -6498,8 +6614,8 @@
         if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
             return;
         }
-        if ((mPrivateFlags2 & ACCESSIBILITY_STATE_CHANGED) == 0) {
-            mPrivateFlags2 |= ACCESSIBILITY_STATE_CHANGED;
+        if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_STATE_CHANGED) == 0) {
+            mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_STATE_CHANGED;
             if (mParent != null) {
                 mParent.childAccessibilityStateChanged(this);
             }
@@ -6513,7 +6629,7 @@
      * @hide
      */
     public void resetAccessibilityStateChanged() {
-        mPrivateFlags2 &= ~ACCESSIBILITY_STATE_CHANGED;
+        mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_STATE_CHANGED;
     }
 
     /**
@@ -6765,7 +6881,7 @@
      */
     public void onStartTemporaryDetach() {
         removeUnsetPressCallback();
-        mPrivateFlags |= CANCEL_NEXT_UP_EVENT;
+        mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT;
     }
 
     /**
@@ -7084,13 +7200,13 @@
             if (isPressed()) {
                 setPressed(false);
             }
-            if (imm != null && (mPrivateFlags & FOCUSED) != 0) {
+            if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) {
                 imm.focusOut(this);
             }
             removeLongPressCallback();
             removeTapCallback();
             onFocusLost();
-        } else if (imm != null && (mPrivateFlags & FOCUSED) != 0) {
+        } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) {
             imm.focusIn(this);
         }
         refreshDrawableState();
@@ -7130,7 +7246,7 @@
             if (mAttachInfo != null) {
                 initialAwakenScrollBars();
             } else {
-                mPrivateFlags |= AWAKEN_SCROLL_BARS_ON_ATTACH;
+                mPrivateFlags |= PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH;
             }
         }
     }
@@ -7231,7 +7347,7 @@
             outRect.bottom -= insets.bottom;
             return;
         }
-        Display d = WindowManagerImpl.getDefault().getDefaultDisplay();
+        Display d = DisplayManager.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
         d.getRectSize(outRect);
     }
 
@@ -7730,7 +7846,7 @@
      */
     @ViewDebug.ExportedProperty
     public boolean isHovered() {
-        return (mPrivateFlags & HOVERED) != 0;
+        return (mPrivateFlags & PFLAG_HOVERED) != 0;
     }
 
     /**
@@ -7750,14 +7866,14 @@
      */
     public void setHovered(boolean hovered) {
         if (hovered) {
-            if ((mPrivateFlags & HOVERED) == 0) {
-                mPrivateFlags |= HOVERED;
+            if ((mPrivateFlags & PFLAG_HOVERED) == 0) {
+                mPrivateFlags |= PFLAG_HOVERED;
                 refreshDrawableState();
                 onHoverChanged(true);
             }
         } else {
-            if ((mPrivateFlags & HOVERED) != 0) {
-                mPrivateFlags &= ~HOVERED;
+            if ((mPrivateFlags & PFLAG_HOVERED) != 0) {
+                mPrivateFlags &= ~PFLAG_HOVERED;
                 refreshDrawableState();
                 onHoverChanged(false);
             }
@@ -7789,7 +7905,7 @@
         final int viewFlags = mViewFlags;
 
         if ((viewFlags & ENABLED_MASK) == DISABLED) {
-            if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PRESSED) != 0) {
+            if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
                 setPressed(false);
             }
             // A disabled view that is clickable still consumes the touch
@@ -7808,8 +7924,8 @@
                 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
             switch (event.getAction()) {
                 case MotionEvent.ACTION_UP:
-                    boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;
-                    if ((mPrivateFlags & PRESSED) != 0 || prepressed) {
+                    boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
+                    if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
                         // take focus if we don't have it already and we should in
                         // touch mode.
                         boolean focusTaken = false;
@@ -7871,7 +7987,7 @@
                     // For views inside a scrolling container, delay the pressed feedback for
                     // a short period in case this is a scroll.
                     if (isInScrollingContainer) {
-                        mPrivateFlags |= PREPRESSED;
+                        mPrivateFlags |= PFLAG_PREPRESSED;
                         if (mPendingCheckForTap == null) {
                             mPendingCheckForTap = new CheckForTap();
                         }
@@ -7896,7 +8012,7 @@
                     if (!pointInView(x, y, mTouchSlop)) {
                         // Outside button
                         removeTapCallback();
-                        if ((mPrivateFlags & PRESSED) != 0) {
+                        if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
                             // Remove any future long press/tap checks
                             removeLongPressCallback();
 
@@ -7947,7 +8063,7 @@
      * Remove the prepress detection timer.
      */
     private void removeUnsetPressCallback() {
-        if ((mPrivateFlags & PRESSED) != 0 && mUnsetPressedState != null) {
+        if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) {
             setPressed(false);
             removeCallbacks(mUnsetPressedState);
         }
@@ -7958,7 +8074,7 @@
      */
     private void removeTapCallback() {
         if (mPendingCheckForTap != null) {
-            mPrivateFlags &= ~PREPRESSED;
+            mPrivateFlags &= ~PFLAG_PREPRESSED;
             removeCallbacks(mPendingCheckForTap);
         }
     }
@@ -8023,13 +8139,13 @@
 
         /* Check if the FOCUSABLE bit has changed */
         if (((changed & FOCUSABLE_MASK) != 0) &&
-                ((privateFlags & HAS_BOUNDS) !=0)) {
+                ((privateFlags & PFLAG_HAS_BOUNDS) !=0)) {
             if (((old & FOCUSABLE_MASK) == FOCUSABLE)
-                    && ((privateFlags & FOCUSED) != 0)) {
+                    && ((privateFlags & PFLAG_FOCUSED) != 0)) {
                 /* Give up focus if we are no longer focusable */
                 clearFocus();
             } else if (((old & FOCUSABLE_MASK) == NOT_FOCUSABLE)
-                    && ((privateFlags & FOCUSED) == 0)) {
+                    && ((privateFlags & PFLAG_FOCUSED) == 0)) {
                 /*
                  * Tell the view system that we are now available to take focus
                  * if no one else already has it.
@@ -8048,7 +8164,7 @@
                  * it was not visible. Marking it drawn ensures that the invalidation will
                  * go through.
                  */
-                mPrivateFlags |= DRAWN;
+                mPrivateFlags |= PFLAG_DRAWN;
                 invalidate(true);
 
                 needGlobalAttributesUpdate(true);
@@ -8078,7 +8194,7 @@
                 }
                 // Mark the view drawn to ensure that it gets invalidated properly the next
                 // time it is visible and gets invalidated
-                mPrivateFlags |= DRAWN;
+                mPrivateFlags |= PFLAG_DRAWN;
             }
             if (mAttachInfo != null) {
                 mAttachInfo.mViewVisibilityChanged = true;
@@ -8092,7 +8208,7 @@
              * If this view is becoming invisible, set the DRAWN flag so that
              * the next invalidate() will not be skipped.
              */
-            mPrivateFlags |= DRAWN;
+            mPrivateFlags |= PFLAG_DRAWN;
 
             if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE) && hasFocus()) {
                 // root view becoming invisible shouldn't clear focus and accessibility focus
@@ -8123,25 +8239,25 @@
 
         if ((changed & DRAWING_CACHE_ENABLED) != 0) {
             destroyDrawingCache();
-            mPrivateFlags &= ~DRAWING_CACHE_VALID;
+            mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
             invalidateParentCaches();
         }
 
         if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) {
             destroyDrawingCache();
-            mPrivateFlags &= ~DRAWING_CACHE_VALID;
+            mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
         }
 
         if ((changed & DRAW_MASK) != 0) {
             if ((mViewFlags & WILL_NOT_DRAW) != 0) {
                 if (mBackground != null) {
-                    mPrivateFlags &= ~SKIP_DRAW;
-                    mPrivateFlags |= ONLY_DRAWS_BACKGROUND;
+                    mPrivateFlags &= ~PFLAG_SKIP_DRAW;
+                    mPrivateFlags |= PFLAG_ONLY_DRAWS_BACKGROUND;
                 } else {
-                    mPrivateFlags |= SKIP_DRAW;
+                    mPrivateFlags |= PFLAG_SKIP_DRAW;
                 }
             } else {
-                mPrivateFlags &= ~SKIP_DRAW;
+                mPrivateFlags &= ~PFLAG_SKIP_DRAW;
             }
             requestLayout();
             invalidate(true);
@@ -8449,7 +8565,7 @@
             // asked for the matrix; recalculate it with the current values
 
             // Figure out if we need to update the pivot point
-            if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
+            if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
                 if ((mRight - mLeft) != info.mPrevWidth || (mBottom - mTop) != info.mPrevHeight) {
                     info.mPrevWidth = mRight - mLeft;
                     info.mPrevHeight = mBottom - mTop;
@@ -8593,7 +8709,7 @@
         if (mDisplayList != null) {
             mDisplayList.setCameraDistance(-Math.abs(distance) / dpi);
         }
-        if ((mPrivateFlags2 & VIEW_QUICK_REJECTED) == VIEW_QUICK_REJECTED) {
+        if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
             // View was rejected last time it was drawn by its parent; this may have changed
             invalidateParentIfNeeded();
         }
@@ -8639,7 +8755,7 @@
             if (mDisplayList != null) {
                 mDisplayList.setRotation(rotation);
             }
-            if ((mPrivateFlags2 & VIEW_QUICK_REJECTED) == VIEW_QUICK_REJECTED) {
+            if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
@@ -8690,7 +8806,7 @@
             if (mDisplayList != null) {
                 mDisplayList.setRotationY(rotationY);
             }
-            if ((mPrivateFlags2 & VIEW_QUICK_REJECTED) == VIEW_QUICK_REJECTED) {
+            if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
@@ -8741,7 +8857,7 @@
             if (mDisplayList != null) {
                 mDisplayList.setRotationX(rotationX);
             }
-            if ((mPrivateFlags2 & VIEW_QUICK_REJECTED) == VIEW_QUICK_REJECTED) {
+            if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
@@ -8784,7 +8900,7 @@
             if (mDisplayList != null) {
                 mDisplayList.setScaleX(scaleX);
             }
-            if ((mPrivateFlags2 & VIEW_QUICK_REJECTED) == VIEW_QUICK_REJECTED) {
+            if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
@@ -8827,7 +8943,7 @@
             if (mDisplayList != null) {
                 mDisplayList.setScaleY(scaleY);
             }
-            if ((mPrivateFlags2 & VIEW_QUICK_REJECTED) == VIEW_QUICK_REJECTED) {
+            if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
@@ -8868,7 +8984,7 @@
      */
     public void setPivotX(float pivotX) {
         ensureTransformationInfo();
-        mPrivateFlags |= PIVOT_EXPLICITLY_SET;
+        mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
         final TransformationInfo info = mTransformationInfo;
         if (info.mPivotX != pivotX) {
             invalidateViewProperty(true, false);
@@ -8878,7 +8994,7 @@
             if (mDisplayList != null) {
                 mDisplayList.setPivotX(pivotX);
             }
-            if ((mPrivateFlags2 & VIEW_QUICK_REJECTED) == VIEW_QUICK_REJECTED) {
+            if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
@@ -8918,7 +9034,7 @@
      */
     public void setPivotY(float pivotY) {
         ensureTransformationInfo();
-        mPrivateFlags |= PIVOT_EXPLICITLY_SET;
+        mPrivateFlags |= PFLAG_PIVOT_EXPLICITLY_SET;
         final TransformationInfo info = mTransformationInfo;
         if (info.mPivotY != pivotY) {
             invalidateViewProperty(true, false);
@@ -8928,7 +9044,7 @@
             if (mDisplayList != null) {
                 mDisplayList.setPivotY(pivotY);
             }
-            if ((mPrivateFlags2 & VIEW_QUICK_REJECTED) == VIEW_QUICK_REJECTED) {
+            if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
@@ -8988,12 +9104,12 @@
         if (mTransformationInfo.mAlpha != alpha) {
             mTransformationInfo.mAlpha = alpha;
             if (onSetAlpha((int) (alpha * 255))) {
-                mPrivateFlags |= ALPHA_SET;
+                mPrivateFlags |= PFLAG_ALPHA_SET;
                 // subclass is handling alpha - don't optimize rendering cache invalidation
                 invalidateParentCaches();
                 invalidate(true);
             } else {
-                mPrivateFlags &= ~ALPHA_SET;
+                mPrivateFlags &= ~PFLAG_ALPHA_SET;
                 invalidateViewProperty(true, false);
                 if (mDisplayList != null) {
                     mDisplayList.setAlpha(alpha);
@@ -9018,10 +9134,10 @@
             mTransformationInfo.mAlpha = alpha;
             boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255));
             if (subclassHandlesAlpha) {
-                mPrivateFlags |= ALPHA_SET;
+                mPrivateFlags |= PFLAG_ALPHA_SET;
                 return true;
             } else {
-                mPrivateFlags &= ~ALPHA_SET;
+                mPrivateFlags &= ~PFLAG_ALPHA_SET;
                 if (mDisplayList != null) {
                     mDisplayList.setAlpha(alpha);
                 }
@@ -9081,16 +9197,16 @@
             onSizeChanged(width, mBottom - mTop, width, oldHeight);
 
             if (!matrixIsIdentity) {
-                if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
+                if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
                     // A change in dimension means an auto-centered pivot point changes, too
                     mTransformationInfo.mMatrixDirty = true;
                 }
-                mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+                mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
                 invalidate(true);
             }
             mBackgroundSizeChanged = true;
             invalidateParentIfNeeded();
-            if ((mPrivateFlags2 & VIEW_QUICK_REJECTED) == VIEW_QUICK_REJECTED) {
+            if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
@@ -9113,7 +9229,7 @@
      * @return The dirty state of this view.
      */
     public boolean isDirty() {
-        return (mPrivateFlags & DIRTY_MASK) != 0;
+        return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0;
     }
 
     /**
@@ -9154,16 +9270,16 @@
             onSizeChanged(width, mBottom - mTop, width, oldHeight);
 
             if (!matrixIsIdentity) {
-                if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
+                if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
                     // A change in dimension means an auto-centered pivot point changes, too
                     mTransformationInfo.mMatrixDirty = true;
                 }
-                mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+                mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
                 invalidate(true);
             }
             mBackgroundSizeChanged = true;
             invalidateParentIfNeeded();
-            if ((mPrivateFlags2 & VIEW_QUICK_REJECTED) == VIEW_QUICK_REJECTED) {
+            if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
@@ -9221,16 +9337,16 @@
             onSizeChanged(mRight - mLeft, height, oldWidth, height);
 
             if (!matrixIsIdentity) {
-                if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
+                if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
                     // A change in dimension means an auto-centered pivot point changes, too
                     mTransformationInfo.mMatrixDirty = true;
                 }
-                mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+                mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
                 invalidate(true);
             }
             mBackgroundSizeChanged = true;
             invalidateParentIfNeeded();
-            if ((mPrivateFlags2 & VIEW_QUICK_REJECTED) == VIEW_QUICK_REJECTED) {
+            if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
@@ -9285,16 +9401,16 @@
             onSizeChanged(mRight - mLeft, height, oldWidth, height);
 
             if (!matrixIsIdentity) {
-                if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
+                if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
                     // A change in dimension means an auto-centered pivot point changes, too
                     mTransformationInfo.mMatrixDirty = true;
                 }
-                mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+                mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
                 invalidate(true);
             }
             mBackgroundSizeChanged = true;
             invalidateParentIfNeeded();
-            if ((mPrivateFlags2 & VIEW_QUICK_REJECTED) == VIEW_QUICK_REJECTED) {
+            if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
@@ -9382,7 +9498,7 @@
             if (mDisplayList != null) {
                 mDisplayList.setTranslationX(translationX);
             }
-            if ((mPrivateFlags2 & VIEW_QUICK_REJECTED) == VIEW_QUICK_REJECTED) {
+            if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
@@ -9423,7 +9539,7 @@
             if (mDisplayList != null) {
                 mDisplayList.setTranslationY(translationY);
             }
-            if ((mPrivateFlags2 & VIEW_QUICK_REJECTED) == VIEW_QUICK_REJECTED) {
+            if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) {
                 // View was rejected last time it was drawn by its parent; this may have changed
                 invalidateParentIfNeeded();
             }
@@ -9657,6 +9773,7 @@
             throw new NullPointerException("Layout parameters cannot be null");
         }
         mLayoutParams = params;
+        resolveLayoutParams();
         if (mParent instanceof ViewGroup) {
             ((ViewGroup) mParent).onSetLayoutParams(this, params);
         }
@@ -9664,6 +9781,15 @@
     }
 
     /**
+     * Resolve the layout parameters depending on the resolved layout direction
+     */
+    private void resolveLayoutParams() {
+        if (mLayoutParams != null) {
+            mLayoutParams.onResolveLayoutDirection(getResolvedLayoutDirection());
+        }
+    }
+
+    /**
      * Set the scrolled position of your view. This will cause a call to
      * {@link #onScrollChanged(int, int, int, int)} and the view will be
      * invalidated.
@@ -9884,12 +10010,12 @@
         if (skipInvalidate()) {
             return;
         }
-        if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
-                (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID ||
-                (mPrivateFlags & INVALIDATED) != INVALIDATED) {
-            mPrivateFlags &= ~DRAWING_CACHE_VALID;
-            mPrivateFlags |= INVALIDATED;
-            mPrivateFlags |= DIRTY;
+        if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) ||
+                (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID ||
+                (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED) {
+            mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
+            mPrivateFlags |= PFLAG_INVALIDATED;
+            mPrivateFlags |= PFLAG_DIRTY;
             final ViewParent p = mParent;
             final AttachInfo ai = mAttachInfo;
             //noinspection PointlessBooleanExpression,ConstantConditions
@@ -9927,12 +10053,12 @@
         if (skipInvalidate()) {
             return;
         }
-        if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
-                (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID ||
-                (mPrivateFlags & INVALIDATED) != INVALIDATED) {
-            mPrivateFlags &= ~DRAWING_CACHE_VALID;
-            mPrivateFlags |= INVALIDATED;
-            mPrivateFlags |= DIRTY;
+        if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) ||
+                (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID ||
+                (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED) {
+            mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
+            mPrivateFlags |= PFLAG_INVALIDATED;
+            mPrivateFlags |= PFLAG_DIRTY;
             final ViewParent p = mParent;
             final AttachInfo ai = mAttachInfo;
             //noinspection PointlessBooleanExpression,ConstantConditions
@@ -9979,15 +10105,15 @@
         if (skipInvalidate()) {
             return;
         }
-        if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
-                (invalidateCache && (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) ||
-                (mPrivateFlags & INVALIDATED) != INVALIDATED || isOpaque() != mLastIsOpaque) {
+        if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) ||
+                (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) ||
+                (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED || isOpaque() != mLastIsOpaque) {
             mLastIsOpaque = isOpaque();
-            mPrivateFlags &= ~DRAWN;
-            mPrivateFlags |= DIRTY;
+            mPrivateFlags &= ~PFLAG_DRAWN;
+            mPrivateFlags |= PFLAG_DIRTY;
             if (invalidateCache) {
-                mPrivateFlags |= INVALIDATED;
-                mPrivateFlags &= ~DRAWING_CACHE_VALID;
+                mPrivateFlags |= PFLAG_INVALIDATED;
+                mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
             }
             final AttachInfo ai = mAttachInfo;
             final ViewParent p = mParent;
@@ -10028,12 +10154,12 @@
      * list properties are not being used in this view
      */
     void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) {
-        if (mDisplayList == null || (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
+        if (mDisplayList == null || (mPrivateFlags & PFLAG_DRAW_ANIMATION) == PFLAG_DRAW_ANIMATION) {
             if (invalidateParent) {
                 invalidateParentCaches();
             }
             if (forceRedraw) {
-                mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+                mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
             }
             invalidate(false);
         } else {
@@ -10077,7 +10203,7 @@
      */
     protected void invalidateParentCaches() {
         if (mParent instanceof View) {
-            ((View) mParent).mPrivateFlags |= INVALIDATED;
+            ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED;
         }
     }
 
@@ -10109,7 +10235,7 @@
      */
     @ViewDebug.ExportedProperty(category = "drawing")
     public boolean isOpaque() {
-        return (mPrivateFlags & OPAQUE_MASK) == OPAQUE_MASK &&
+        return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK &&
                 ((mTransformationInfo != null ? mTransformationInfo.mAlpha : 1.0f) >= 1.0f);
     }
 
@@ -10123,17 +10249,17 @@
         //   - Doesn't have scrollbars or scrollbars are inside overlay
 
         if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) {
-            mPrivateFlags |= OPAQUE_BACKGROUND;
+            mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND;
         } else {
-            mPrivateFlags &= ~OPAQUE_BACKGROUND;
+            mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND;
         }
 
         final int flags = mViewFlags;
         if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) ||
                 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY) {
-            mPrivateFlags |= OPAQUE_SCROLLBARS;
+            mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS;
         } else {
-            mPrivateFlags &= ~OPAQUE_SCROLLBARS;
+            mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS;
         }
     }
 
@@ -10141,7 +10267,7 @@
      * @hide
      */
     protected boolean hasOpaqueScrollbars() {
-        return (mPrivateFlags & OPAQUE_SCROLLBARS) == OPAQUE_SCROLLBARS;
+        return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS;
     }
 
     /**
@@ -11186,23 +11312,18 @@
      * @see #onDetachedFromWindow()
      */
     protected void onAttachedToWindow() {
-        if ((mPrivateFlags & REQUEST_TRANSPARENT_REGIONS) != 0) {
+        if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
             mParent.requestTransparentRegion(this);
         }
 
-        if ((mPrivateFlags & AWAKEN_SCROLL_BARS_ON_ATTACH) != 0) {
+        if ((mPrivateFlags & PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH) != 0) {
             initialAwakenScrollBars();
-            mPrivateFlags &= ~AWAKEN_SCROLL_BARS_ON_ATTACH;
+            mPrivateFlags &= ~PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH;
         }
 
         jumpDrawablesToCurrentState();
 
-        // Order is important here: LayoutDirection MUST be resolved before Padding
-        // and TextDirection
-        resolveLayoutDirection();
-        resolvePadding();
-        resolveTextDirection();
-        resolveTextAlignment();
+        resolveRtlProperties();
 
         clearAccessibilityFocus();
         if (isFocused()) {
@@ -11215,6 +11336,16 @@
         }
     }
 
+    void resolveRtlProperties() {
+        // Order is important here: LayoutDirection MUST be resolved first...
+        resolveLayoutDirection();
+        // ... then we can resolve the others properties depending on the resolved LayoutDirection.
+        resolvePadding();
+        resolveLayoutParams();
+        resolveTextDirection();
+        resolveTextAlignment();
+    }
+
     /**
      * @see #onScreenStateChanged(int)
      */
@@ -11248,7 +11379,7 @@
      */
     public void resolveLayoutDirection() {
         // Clear any previous layout direction resolution
-        mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED_MASK;
+        mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK;
 
         if (hasRtlSupport()) {
             // Set resolved depending on layout direction
@@ -11265,15 +11396,15 @@
                     if (!viewGroup.canResolveLayoutDirection()) return;
 
                     if (viewGroup.getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) {
-                        mPrivateFlags2 |= LAYOUT_DIRECTION_RESOLVED_RTL;
+                        mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL;
                     }
                     break;
                 case LAYOUT_DIRECTION_RTL:
-                    mPrivateFlags2 |= LAYOUT_DIRECTION_RESOLVED_RTL;
+                    mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL;
                     break;
                 case LAYOUT_DIRECTION_LOCALE:
                     if(isLayoutDirectionRtl(Locale.getDefault())) {
-                        mPrivateFlags2 |= LAYOUT_DIRECTION_RESOLVED_RTL;
+                        mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL;
                     }
                     break;
                 default:
@@ -11282,7 +11413,7 @@
         }
 
         // Set to resolved
-        mPrivateFlags2 |= LAYOUT_DIRECTION_RESOLVED;
+        mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED;
         onResolvedLayoutDirectionChanged();
     }
 
@@ -11295,56 +11426,66 @@
     }
 
     /**
+     * Return if padding has been resolved
+     */
+    boolean isPaddingResolved() {
+        return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) != 0;
+    }
+
+    /**
      * Resolve padding depending on layout direction.
      */
     public void resolvePadding() {
-        // If the user specified the absolute padding (either with android:padding or
-        // android:paddingLeft/Top/Right/Bottom), use this padding, otherwise
-        // use the default padding or the padding from the background drawable
-        // (stored at this point in mPadding*)
-        int resolvedLayoutDirection = getResolvedLayoutDirection();
-        switch (resolvedLayoutDirection) {
-            case LAYOUT_DIRECTION_RTL:
-                // Start user padding override Right user padding. Otherwise, if Right user
-                // padding is not defined, use the default Right padding. If Right user padding
-                // is defined, just use it.
-                if (mUserPaddingStart != UNDEFINED_PADDING) {
-                    mUserPaddingRight = mUserPaddingStart;
-                }
-                if (mUserPaddingRight == UNDEFINED_PADDING) {
-                    mUserPaddingRight = mPaddingRight;
-                }
-                if (mUserPaddingEnd != UNDEFINED_PADDING) {
-                    mUserPaddingLeft = mUserPaddingEnd;
-                }
-                if (mUserPaddingLeft == UNDEFINED_PADDING) {
-                    mUserPaddingLeft = mPaddingLeft;
-                }
-                break;
-            case LAYOUT_DIRECTION_LTR:
-            default:
-                // Start user padding override Left user padding. Otherwise, if Left user
-                // padding is not defined, use the default left padding. If Left user padding
-                // is defined, just use it.
-                if (mUserPaddingStart != UNDEFINED_PADDING) {
-                    mUserPaddingLeft = mUserPaddingStart;
-                }
-                if (mUserPaddingLeft == UNDEFINED_PADDING) {
-                    mUserPaddingLeft = mPaddingLeft;
-                }
-                if (mUserPaddingEnd != UNDEFINED_PADDING) {
-                    mUserPaddingRight = mUserPaddingEnd;
-                }
-                if (mUserPaddingRight == UNDEFINED_PADDING) {
-                    mUserPaddingRight = mPaddingRight;
-                }
+        final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
+        if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport()) {
+            // Pre Jelly Bean MR1 case (compatibility mode) OR no RTL support case:
+            // left / right padding are used if defined. If they are not defined and start / end
+            // padding are defined (e.g. in Frameworks resources), then we use start / end and
+            // resolve them as left / right (layout direction is not taken into account).
+            if (!mUserPaddingLeftDefined && mUserPaddingStart != UNDEFINED_PADDING) {
+                mUserPaddingLeft = mUserPaddingStart;
+            }
+            if (!mUserPaddingRightDefined && mUserPaddingEnd != UNDEFINED_PADDING) {
+                mUserPaddingRight = mUserPaddingEnd;
+            }
+
+            mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom;
+
+            internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight,
+                    mUserPaddingBottom);
+        } else {
+            // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account.
+            // If start / end padding are defined, they will be resolved (hence overriding) to
+            // 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 = getResolvedLayoutDirection();
+            switch (resolvedLayoutDirection) {
+                case LAYOUT_DIRECTION_RTL:
+                    if (mUserPaddingStart != UNDEFINED_PADDING) {
+                        mUserPaddingRight = mUserPaddingStart;
+                    }
+                    if (mUserPaddingEnd != UNDEFINED_PADDING) {
+                        mUserPaddingLeft = mUserPaddingEnd;
+                    }
+                    break;
+                case LAYOUT_DIRECTION_LTR:
+                default:
+                    if (mUserPaddingStart != UNDEFINED_PADDING) {
+                        mUserPaddingLeft = mUserPaddingStart;
+                    }
+                    if (mUserPaddingEnd != UNDEFINED_PADDING) {
+                        mUserPaddingRight = mUserPaddingEnd;
+                    }
+            }
+
+            mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom;
+
+            internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight,
+                    mUserPaddingBottom);
+            onPaddingChanged(resolvedLayoutDirection);
         }
 
-        mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom;
-
-        internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom);
-        onPaddingChanged(resolvedLayoutDirection);
-        mPrivateFlags2 |= PADDING_RESOLVED;
+        mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED;
     }
 
     /**
@@ -11380,7 +11521,7 @@
      */
     public void resetResolvedLayoutDirection() {
         // Reset the current resolved bits
-        mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED_MASK;
+        mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK;
         onResolvedLayoutDirectionReset();
         // Reset also the text direction
         resetResolvedTextDirection();
@@ -11414,7 +11555,7 @@
      * @see #onAttachedToWindow()
      */
     protected void onDetachedFromWindow() {
-        mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
+        mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
 
         removeUnsetPressCallback();
         removeLongPressCallback();
@@ -11440,7 +11581,7 @@
         resetResolvedLayoutDirection();
         resetResolvedTextAlignment();
         resetAccessibilityStateChanged();
-        mPrivateFlags2 &= ~PADDING_RESOLVED;
+        mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED;
     }
 
     /**
@@ -11482,6 +11623,15 @@
     }
 
     /**
+     * Gets the logical display to which the view's window has been attached.
+     *
+     * @return The logical display, or null if the view is not currently attached to a window.
+     */
+    public Display getDisplay() {
+        return mAttachInfo != null ? mAttachInfo.mDisplay : null;
+    }
+
+    /**
      * Retrieve private session object this view hierarchy is using to
      * communicate with the window manager.
      * @return the session object to communicate with the window manager
@@ -11499,14 +11649,14 @@
         mAttachInfo = info;
         mWindowAttachCount++;
         // We will need to evaluate the drawable state at least once.
-        mPrivateFlags |= DRAWABLE_STATE_DIRTY;
+        mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY;
         if (mFloatingTreeObserver != null) {
             info.mTreeObserver.merge(mFloatingTreeObserver);
             mFloatingTreeObserver = null;
         }
-        if ((mPrivateFlags&SCROLL_CONTAINER) != 0) {
+        if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) {
             mAttachInfo.mScrollContainers.add(this);
-            mPrivateFlags |= SCROLL_CONTAINER_ADDED;
+            mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED;
         }
         performCollectViewAttributes(mAttachInfo, visibility);
         onAttachedToWindow();
@@ -11528,7 +11678,7 @@
         if (vis != GONE) {
             onWindowVisibilityChanged(vis);
         }
-        if ((mPrivateFlags&DRAWABLE_STATE_DIRTY) != 0) {
+        if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) {
             // If nobody has evaluated the drawable state yet, then do it now.
             refreshDrawableState();
         }
@@ -11558,9 +11708,9 @@
             }
         }
 
-        if ((mPrivateFlags & SCROLL_CONTAINER_ADDED) != 0) {
+        if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) {
             mAttachInfo.mScrollContainers.remove(this);
-            mPrivateFlags &= ~SCROLL_CONTAINER_ADDED;
+            mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED;
         }
 
         mAttachInfo = null;
@@ -11592,9 +11742,9 @@
      */
     protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
         if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
-            mPrivateFlags &= ~SAVE_STATE_CALLED;
+            mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
             Parcelable state = onSaveInstanceState();
-            if ((mPrivateFlags & SAVE_STATE_CALLED) == 0) {
+            if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
                 throw new IllegalStateException(
                         "Derived class did not call super.onSaveInstanceState()");
             }
@@ -11628,7 +11778,7 @@
      * @see #setSaveEnabled(boolean)
      */
     protected Parcelable onSaveInstanceState() {
-        mPrivateFlags |= SAVE_STATE_CALLED;
+        mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
         return BaseSavedState.EMPTY_STATE;
     }
 
@@ -11663,9 +11813,9 @@
             if (state != null) {
                 // Log.i("View", "Restoreing #" + Integer.toHexString(mID)
                 // + ": " + state);
-                mPrivateFlags &= ~SAVE_STATE_CALLED;
+                mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
                 onRestoreInstanceState(state);
-                if ((mPrivateFlags & SAVE_STATE_CALLED) == 0) {
+                if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
                     throw new IllegalStateException(
                             "Derived class did not call super.onRestoreInstanceState()");
                 }
@@ -11686,7 +11836,7 @@
      * @see #dispatchRestoreInstanceState(android.util.SparseArray)
      */
     protected void onRestoreInstanceState(Parcelable state) {
-        mPrivateFlags |= SAVE_STATE_CALLED;
+        mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
         if (state != BaseSavedState.EMPTY_STATE && state != null) {
             throw new IllegalArgumentException("Wrong state class, expecting View State but "
                     + "received " + state.getClass().toString() + " instead. This usually happens "
@@ -11901,7 +12051,7 @@
             return null;
         }
 
-        if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || mHardwareLayer == null) {
+        if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || mHardwareLayer == null) {
             if (mHardwareLayer == null) {
                 mHardwareLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
                         width, height, isOpaque());
@@ -12031,10 +12181,10 @@
      */
     @SuppressWarnings({"UnusedDeclaration"})
     public void outputDirtyFlags(String indent, boolean clear, int clearMask) {
-        Log.d("View", indent + this + "             DIRTY(" + (mPrivateFlags & View.DIRTY_MASK) +
-                ") DRAWN(" + (mPrivateFlags & DRAWN) + ")" + " CACHE_VALID(" +
-                (mPrivateFlags & View.DRAWING_CACHE_VALID) +
-                ") INVALIDATED(" + (mPrivateFlags & INVALIDATED) + ")");
+        Log.d("View", indent + this + "             DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) +
+                ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" +
+                (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) +
+                ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")");
         if (clear) {
             mPrivateFlags &= clearMask;
         }
@@ -12098,15 +12248,15 @@
             return null;
         }
 
-        if (((mPrivateFlags & DRAWING_CACHE_VALID) == 0 ||
+        if (((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 ||
                 displayList == null || !displayList.isValid() ||
                 (!isLayer && mRecreateDisplayList))) {
             // Don't need to recreate the display list, just need to tell our
             // children to restore/recreate theirs
             if (displayList != null && displayList.isValid() &&
                     !isLayer && !mRecreateDisplayList) {
-                mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
-                mPrivateFlags &= ~DIRTY_MASK;
+                mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
+                mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                 dispatchGetDisplayList();
 
                 return displayList;
@@ -12161,12 +12311,12 @@
 
                     canvas.translate(-mScrollX, -mScrollY);
                     if (!isLayer) {
-                        mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
-                        mPrivateFlags &= ~DIRTY_MASK;
+                        mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
+                        mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                     }
 
                     // Fast path for layouts with no backgrounds
-                    if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
+                    if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
                         dispatchDraw(canvas);
                     } else {
                         draw(canvas);
@@ -12184,8 +12334,8 @@
                 }
             }
         } else if (!isLayer) {
-            mPrivateFlags |= DRAWN | DRAWING_CACHE_VALID;
-            mPrivateFlags &= ~DIRTY_MASK;
+            mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
+            mPrivateFlags &= ~PFLAG_DIRTY_MASK;
         }
 
         return displayList;
@@ -12307,7 +12457,7 @@
     public void setDrawingCacheBackgroundColor(int color) {
         if (color != mDrawingCacheBackgroundColor) {
             mDrawingCacheBackgroundColor = color;
-            mPrivateFlags &= ~DRAWING_CACHE_VALID;
+            mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
         }
     }
 
@@ -12353,7 +12503,7 @@
      * @see #destroyDrawingCache()
      */
     public void buildDrawingCache(boolean autoScale) {
-        if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || (autoScale ?
+        if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ?
                 mDrawingCache == null : mUnscaledDrawingCache == null)) {
             mCachingFailed = false;
 
@@ -12469,15 +12619,15 @@
 
             canvas.translate(-mScrollX, -mScrollY);
 
-            mPrivateFlags |= DRAWN;
+            mPrivateFlags |= PFLAG_DRAWN;
             if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated ||
                     mLayerType != LAYER_TYPE_NONE) {
-                mPrivateFlags |= DRAWING_CACHE_VALID;
+                mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID;
             }
 
             // Fast path for layouts with no backgrounds
-            if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
-                mPrivateFlags &= ~DIRTY_MASK;
+            if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
+                mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                 dispatchDraw(canvas);
             } else {
                 draw(canvas);
@@ -12545,10 +12695,10 @@
 
         // Temporarily remove the dirty mask
         int flags = mPrivateFlags;
-        mPrivateFlags &= ~DIRTY_MASK;
+        mPrivateFlags &= ~PFLAG_DIRTY_MASK;
 
         // Fast path for layouts with no backgrounds
-        if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
+        if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
             dispatchDraw(canvas);
         } else {
             draw(canvas);
@@ -12738,7 +12888,7 @@
                 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) {
                     // The child need to draw an animation, potentially offscreen, so
                     // make sure we do not cancel invalidate requests
-                    parent.mPrivateFlags |= DRAW_ANIMATION;
+                    parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
                     parent.invalidate(mLeft, mTop, mRight, mBottom);
                 }
             } else {
@@ -12751,7 +12901,7 @@
 
                 // The child need to draw an animation, potentially offscreen, so
                 // make sure we do not cancel invalidate requests
-                parent.mPrivateFlags |= DRAW_ANIMATION;
+                parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
 
                 final int left = mLeft + (int) region.left;
                 final int top = mTop + (int) region.top;
@@ -12813,7 +12963,7 @@
                     mTransformationInfo.matrix3D = new Matrix();
                 }
                 displayList.setCameraDistance(mTransformationInfo.mCamera.getLocationZ());
-                if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == PIVOT_EXPLICITLY_SET) {
+                if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == PFLAG_PIVOT_EXPLICITLY_SET) {
                     displayList.setPivotX(getPivotX());
                     displayList.setPivotY(getPivotY());
                 }
@@ -12861,15 +13011,15 @@
             more = drawAnimation(parent, drawingTime, a, scalingRequired);
             concatMatrix = a.willChangeTransformationMatrix();
             if (concatMatrix) {
-                mPrivateFlags3 |= VIEW_IS_ANIMATING_TRANSFORM;
+                mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
             }
             transformToApply = parent.mChildTransformation;
         } else {
-            if ((mPrivateFlags3 & VIEW_IS_ANIMATING_TRANSFORM) == VIEW_IS_ANIMATING_TRANSFORM &&
+            if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) == PFLAG3_VIEW_IS_ANIMATING_TRANSFORM &&
                     mDisplayList != null) {
                 // No longer animating: clear out old animation matrix
                 mDisplayList.setAnimationMatrix(null);
-                mPrivateFlags3 &= ~VIEW_IS_ANIMATING_TRANSFORM;
+                mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
             }
             if (!useDisplayListProperties &&
                     (flags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
@@ -12888,21 +13038,21 @@
 
         // Sets the flag as early as possible to allow draw() implementations
         // to call invalidate() successfully when doing animations
-        mPrivateFlags |= DRAWN;
+        mPrivateFlags |= PFLAG_DRAWN;
 
         if (!concatMatrix && (flags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) == 0 &&
                 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) &&
-                (mPrivateFlags & DRAW_ANIMATION) == 0) {
-            mPrivateFlags2 |= VIEW_QUICK_REJECTED;
+                (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) {
+            mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED;
             return more;
         }
-        mPrivateFlags2 &= ~VIEW_QUICK_REJECTED;
+        mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED;
 
         if (hardwareAccelerated) {
             // Clear INVALIDATED flag to allow invalidation to occur during rendering, but
             // retain the flag's value temporarily in the mRecreateDisplayList flag
-            mRecreateDisplayList = (mPrivateFlags & INVALIDATED) == INVALIDATED;
-            mPrivateFlags &= ~INVALIDATED;
+            mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) == PFLAG_INVALIDATED;
+            mPrivateFlags &= ~PFLAG_INVALIDATED;
         }
 
         DisplayList displayList = null;
@@ -12986,7 +13136,7 @@
 
         float alpha = useDisplayListProperties ? 1 : getAlpha();
         if (transformToApply != null || alpha < 1 || !hasIdentityMatrix() ||
-                (mPrivateFlags3 & VIEW_IS_ANIMATING_ALPHA) == VIEW_IS_ANIMATING_ALPHA) {
+                (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) == PFLAG3_VIEW_IS_ANIMATING_ALPHA) {
             if (transformToApply != null || !childHasIdentityMatrix) {
                 int transX = 0;
                 int transY = 0;
@@ -13026,11 +13176,11 @@
 
             // Deal with alpha if it is or used to be <1
             if (alpha < 1 ||
-                    (mPrivateFlags3 & VIEW_IS_ANIMATING_ALPHA) == VIEW_IS_ANIMATING_ALPHA) {
+                    (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) == PFLAG3_VIEW_IS_ANIMATING_ALPHA) {
                 if (alpha < 1) {
-                    mPrivateFlags3 |= VIEW_IS_ANIMATING_ALPHA;
+                    mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA;
                 } else {
-                    mPrivateFlags3 &= ~VIEW_IS_ANIMATING_ALPHA;
+                    mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA;
                 }
                 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
                 if (hasNoCache) {
@@ -13051,13 +13201,13 @@
                         }
                     } else {
                         // Alpha is handled by the child directly, clobber the layer's alpha
-                        mPrivateFlags |= ALPHA_SET;
+                        mPrivateFlags |= PFLAG_ALPHA_SET;
                     }
                 }
             }
-        } else if ((mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
+        } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) {
             onSetAlpha(255);
-            mPrivateFlags &= ~ALPHA_SET;
+            mPrivateFlags &= ~PFLAG_ALPHA_SET;
         }
 
         if ((flags & ViewGroup.FLAG_CLIP_CHILDREN) == ViewGroup.FLAG_CLIP_CHILDREN &&
@@ -13104,19 +13254,19 @@
             if (!layerRendered) {
                 if (!hasDisplayList) {
                     // Fast path for layouts with no backgrounds
-                    if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
-                        mPrivateFlags &= ~DIRTY_MASK;
+                    if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
+                        mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                         dispatchDraw(canvas);
                     } else {
                         draw(canvas);
                     }
                 } else {
-                    mPrivateFlags &= ~DIRTY_MASK;
+                    mPrivateFlags &= ~PFLAG_DIRTY_MASK;
                     ((HardwareCanvas) canvas).drawDisplayList(displayList, null, flags);
                 }
             }
         } else if (cache != null) {
-            mPrivateFlags &= ~DIRTY_MASK;
+            mPrivateFlags &= ~PFLAG_DIRTY_MASK;
             Paint cachePaint;
 
             if (layerType == LAYER_TYPE_NONE) {
@@ -13156,7 +13306,7 @@
             // display lists to render, force an invalidate to allow the animation to
             // continue drawing another frame
             parent.invalidate(true);
-            if (a.hasAlpha() && (mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
+            if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) {
                 // alpha animations should cause the child to recreate its display list
                 invalidate(true);
             }
@@ -13178,9 +13328,9 @@
      */
     public void draw(Canvas canvas) {
         final int privateFlags = mPrivateFlags;
-        final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) == DIRTY_OPAQUE &&
+        final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
                 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
-        mPrivateFlags = (privateFlags & ~DIRTY_MASK) | DRAWN;
+        mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
 
         /*
          * Draw traversal performs several drawing steps which must be executed
@@ -13435,12 +13585,12 @@
         String output = "";
         int numFlags = 0;
 
-        if ((privateFlags & WANTS_FOCUS) == WANTS_FOCUS) {
+        if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) {
             output += "WANTS_FOCUS";
             numFlags++;
         }
 
-        if ((privateFlags & FOCUSED) == FOCUSED) {
+        if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) {
             if (numFlags > 0) {
                 output += " ";
             }
@@ -13448,7 +13598,7 @@
             numFlags++;
         }
 
-        if ((privateFlags & SELECTED) == SELECTED) {
+        if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) {
             if (numFlags > 0) {
                 output += " ";
             }
@@ -13456,7 +13606,7 @@
             numFlags++;
         }
 
-        if ((privateFlags & IS_ROOT_NAMESPACE) == IS_ROOT_NAMESPACE) {
+        if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) {
             if (numFlags > 0) {
                 output += " ";
             }
@@ -13464,7 +13614,7 @@
             numFlags++;
         }
 
-        if ((privateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
+        if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) {
             if (numFlags > 0) {
                 output += " ";
             }
@@ -13472,7 +13622,7 @@
             numFlags++;
         }
 
-        if ((privateFlags & DRAWN) == DRAWN) {
+        if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) {
             if (numFlags > 0) {
                 output += " ";
             }
@@ -13489,7 +13639,7 @@
      * @return true if the layout will be forced during next layout pass
      */
     public boolean isLayoutRequested() {
-        return (mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT;
+        return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;
     }
 
     /**
@@ -13519,9 +13669,9 @@
         int oldB = mBottom;
         int oldR = mRight;
         boolean changed = setFrame(l, t, r, b);
-        if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {
+        if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
             onLayout(changed, l, t, r, b);
-            mPrivateFlags &= ~LAYOUT_REQUIRED;
+            mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;
 
             ListenerInfo li = mListenerInfo;
             if (li != null && li.mOnLayoutChangeListeners != null) {
@@ -13533,7 +13683,7 @@
                 }
             }
         }
-        mPrivateFlags &= ~FORCE_LAYOUT;
+        mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;
     }
 
     /**
@@ -13577,7 +13727,7 @@
             changed = true;
 
             // Remember our drawn bit
-            int drawn = mPrivateFlags & DRAWN;
+            int drawn = mPrivateFlags & PFLAG_DRAWN;
 
             int oldWidth = mRight - mLeft;
             int oldHeight = mBottom - mTop;
@@ -13596,11 +13746,11 @@
                 mDisplayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);
             }
 
-            mPrivateFlags |= HAS_BOUNDS;
+            mPrivateFlags |= PFLAG_HAS_BOUNDS;
 
 
             if (sizeChanged) {
-                if ((mPrivateFlags & PIVOT_EXPLICITLY_SET) == 0) {
+                if ((mPrivateFlags & PFLAG_PIVOT_EXPLICITLY_SET) == 0) {
                     // A change in dimension means an auto-centered pivot point changes, too
                     if (mTransformationInfo != null) {
                         mTransformationInfo.mMatrixDirty = true;
@@ -13615,7 +13765,7 @@
                 // This is because someone may have invalidated this view
                 // before this call to setFrame came in, thereby clearing
                 // the DRAWN bit.
-                mPrivateFlags |= DRAWN;
+                mPrivateFlags |= PFLAG_DRAWN;
                 invalidate(sizeChanged);
                 // parent display list may need to be recreated based on a change in the bounds
                 // of any child
@@ -13793,7 +13943,7 @@
      * @see #getDrawableState
      */
     public void refreshDrawableState() {
-        mPrivateFlags |= DRAWABLE_STATE_DIRTY;
+        mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY;
         drawableStateChanged();
 
         ViewParent parent = mParent;
@@ -13813,11 +13963,11 @@
      * @see #onCreateDrawableState(int)
      */
     public final int[] getDrawableState() {
-        if ((mDrawableState != null) && ((mPrivateFlags & DRAWABLE_STATE_DIRTY) == 0)) {
+        if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) {
             return mDrawableState;
         } else {
             mDrawableState = onCreateDrawableState(0);
-            mPrivateFlags &= ~DRAWABLE_STATE_DIRTY;
+            mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY;
             return mDrawableState;
         }
     }
@@ -13848,12 +13998,12 @@
         int privateFlags = mPrivateFlags;
 
         int viewStateIndex = 0;
-        if ((privateFlags & PRESSED) != 0) viewStateIndex |= VIEW_STATE_PRESSED;
+        if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= VIEW_STATE_PRESSED;
         if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= VIEW_STATE_ENABLED;
         if (isFocused()) viewStateIndex |= VIEW_STATE_FOCUSED;
-        if ((privateFlags & SELECTED) != 0) viewStateIndex |= VIEW_STATE_SELECTED;
+        if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= VIEW_STATE_SELECTED;
         if (hasWindowFocus()) viewStateIndex |= VIEW_STATE_WINDOW_FOCUSED;
-        if ((privateFlags & ACTIVATED) != 0) viewStateIndex |= VIEW_STATE_ACTIVATED;
+        if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= VIEW_STATE_ACTIVATED;
         if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested &&
                 HardwareRenderer.isAvailable()) {
             // This is set if HW acceleration is requested, even if the current
@@ -13861,11 +14011,11 @@
             // windows to better match their app.
             viewStateIndex |= VIEW_STATE_ACCELERATED;
         }
-        if ((privateFlags & HOVERED) != 0) viewStateIndex |= VIEW_STATE_HOVERED;
+        if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= VIEW_STATE_HOVERED;
 
         final int privateFlags2 = mPrivateFlags2;
-        if ((privateFlags2 & DRAG_CAN_ACCEPT) != 0) viewStateIndex |= VIEW_STATE_DRAG_CAN_ACCEPT;
-        if ((privateFlags2 & DRAG_HOVERED) != 0) viewStateIndex |= VIEW_STATE_DRAG_HOVERED;
+        if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) viewStateIndex |= VIEW_STATE_DRAG_CAN_ACCEPT;
+        if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) viewStateIndex |= VIEW_STATE_DRAG_HOVERED;
 
         drawableState = VIEW_STATE_SETS[viewStateIndex];
 
@@ -13873,10 +14023,10 @@
         if (false) {
             Log.i("View", "drawableStateIndex=" + viewStateIndex);
             Log.i("View", toString()
-                    + " pressed=" + ((privateFlags & PRESSED) != 0)
+                    + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0)
                     + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED)
                     + " fo=" + hasFocus()
-                    + " sl=" + ((privateFlags & SELECTED) != 0)
+                    + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0)
                     + " wf=" + hasWindowFocus()
                     + ": " + Arrays.toString(drawableState));
         }
@@ -14016,6 +14166,8 @@
             }
             background.setLayoutDirection(getResolvedLayoutDirection());
             if (background.getPadding(padding)) {
+                // Reset padding resolution
+                mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED;
                 switch (background.getLayoutDirection()) {
                     case LAYOUT_DIRECTION_RTL:
                         internalSetPadding(padding.right, padding.top, padding.left, padding.bottom);
@@ -14040,23 +14192,23 @@
             background.setVisible(getVisibility() == VISIBLE, false);
             mBackground = background;
 
-            if ((mPrivateFlags & SKIP_DRAW) != 0) {
-                mPrivateFlags &= ~SKIP_DRAW;
-                mPrivateFlags |= ONLY_DRAWS_BACKGROUND;
+            if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) {
+                mPrivateFlags &= ~PFLAG_SKIP_DRAW;
+                mPrivateFlags |= PFLAG_ONLY_DRAWS_BACKGROUND;
                 requestLayout = true;
             }
         } else {
             /* Remove the background */
             mBackground = null;
 
-            if ((mPrivateFlags & ONLY_DRAWS_BACKGROUND) != 0) {
+            if ((mPrivateFlags & PFLAG_ONLY_DRAWS_BACKGROUND) != 0) {
                 /*
                  * This view ONLY drew the background before and we're removing
                  * the background, so now it won't draw anything
                  * (hence we SKIP_DRAW)
                  */
-                mPrivateFlags &= ~ONLY_DRAWS_BACKGROUND;
-                mPrivateFlags |= SKIP_DRAW;
+                mPrivateFlags &= ~PFLAG_ONLY_DRAWS_BACKGROUND;
+                mPrivateFlags |= PFLAG_SKIP_DRAW;
             }
 
             /*
@@ -14112,13 +14264,19 @@
      * @param bottom the bottom padding in pixels
      */
     public void setPadding(int left, int top, int right, int bottom) {
+        // Reset padding resolution
+        mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED;
+
         mUserPaddingStart = UNDEFINED_PADDING;
         mUserPaddingEnd = UNDEFINED_PADDING;
 
         internalSetPadding(left, top, right, bottom);
     }
 
-    void internalSetPadding(int left, int top, int right, int bottom) {
+    /**
+     * @hide
+     */
+    protected void internalSetPadding(int left, int top, int right, int bottom) {
         mUserPaddingLeft = left;
         mUserPaddingRight = right;
         mUserPaddingBottom = bottom;
@@ -14193,6 +14351,9 @@
      * @param bottom the bottom padding in pixels
      */
     public void setPaddingRelative(int start, int top, int end, int bottom) {
+        // Reset padding resolution
+        mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED;
+
         mUserPaddingStart = start;
         mUserPaddingEnd = end;
 
@@ -14234,6 +14395,9 @@
      * @return the left padding in pixels
      */
     public int getPaddingLeft() {
+        if (!isPaddingResolved()) {
+            resolvePadding();
+        }
         return mPaddingLeft;
     }
 
@@ -14245,6 +14409,9 @@
      * @return the start padding in pixels
      */
     public int getPaddingStart() {
+        if (!isPaddingResolved()) {
+            resolvePadding();
+        }
         return (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
                 mPaddingRight : mPaddingLeft;
     }
@@ -14257,6 +14424,9 @@
      * @return the right padding in pixels
      */
     public int getPaddingRight() {
+        if (!isPaddingResolved()) {
+            resolvePadding();
+        }
         return mPaddingRight;
     }
 
@@ -14268,6 +14438,9 @@
      * @return the end padding in pixels
      */
     public int getPaddingEnd() {
+        if (!isPaddingResolved()) {
+            resolvePadding();
+        }
         return (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
                 mPaddingLeft : mPaddingRight;
     }
@@ -14310,8 +14483,8 @@
      * @param selected true if the view must be selected, false otherwise
      */
     public void setSelected(boolean selected) {
-        if (((mPrivateFlags & SELECTED) != 0) != selected) {
-            mPrivateFlags = (mPrivateFlags & ~SELECTED) | (selected ? SELECTED : 0);
+        if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) {
+            mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0);
             if (!selected) resetPressedState();
             invalidate(true);
             refreshDrawableState();
@@ -14339,7 +14512,7 @@
      */
     @ViewDebug.ExportedProperty
     public boolean isSelected() {
-        return (mPrivateFlags & SELECTED) != 0;
+        return (mPrivateFlags & PFLAG_SELECTED) != 0;
     }
 
     /**
@@ -14356,8 +14529,8 @@
      * @param activated true if the view must be activated, false otherwise
      */
     public void setActivated(boolean activated) {
-        if (((mPrivateFlags & ACTIVATED) != 0) != activated) {
-            mPrivateFlags = (mPrivateFlags & ~ACTIVATED) | (activated ? ACTIVATED : 0);
+        if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) {
+            mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0);
             invalidate(true);
             refreshDrawableState();
             dispatchSetActivated(activated);
@@ -14381,7 +14554,7 @@
      */
     @ViewDebug.ExportedProperty
     public boolean isActivated() {
-        return (mPrivateFlags & ACTIVATED) != 0;
+        return (mPrivateFlags & PFLAG_ACTIVATED) != 0;
     }
 
     /**
@@ -14669,9 +14842,9 @@
      */
     public void setIsRootNamespace(boolean isRoot) {
         if (isRoot) {
-            mPrivateFlags |= IS_ROOT_NAMESPACE;
+            mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE;
         } else {
-            mPrivateFlags &= ~IS_ROOT_NAMESPACE;
+            mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE;
         }
     }
 
@@ -14681,7 +14854,7 @@
      * @return true if the view belongs to the root namespace, false otherwise
      */
     public boolean isRootNamespace() {
-        return (mPrivateFlags&IS_ROOT_NAMESPACE) != 0;
+        return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0;
     }
 
     /**
@@ -14830,7 +15003,7 @@
         }
         Log.d(VIEW_LOG_TAG, output);
 
-        if ((mPrivateFlags & FOCUSED) != 0) {
+        if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
             output = debugIndent(depth) + " FOCUSED";
             Log.d(VIEW_LOG_TAG, output);
         }
@@ -14910,12 +15083,8 @@
      * tree.
      */
     public void requestLayout() {
-        mPrivateFlags |= FORCE_LAYOUT;
-        mPrivateFlags |= INVALIDATED;
-
-        if (mLayoutParams != null) {
-            mLayoutParams.onResolveLayoutDirection(getResolvedLayoutDirection());
-        }
+        mPrivateFlags |= PFLAG_FORCE_LAYOUT;
+        mPrivateFlags |= PFLAG_INVALIDATED;
 
         if (mParent != null && !mParent.isLayoutRequested()) {
             mParent.requestLayout();
@@ -14928,8 +15097,8 @@
      * on the parent.
      */
     public void forceLayout() {
-        mPrivateFlags |= FORCE_LAYOUT;
-        mPrivateFlags |= INVALIDATED;
+        mPrivateFlags |= PFLAG_FORCE_LAYOUT;
+        mPrivateFlags |= PFLAG_INVALIDATED;
     }
 
     /**
@@ -14953,14 +15122,14 @@
      * @see #onMeasure(int, int)
      */
     public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
-        if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT ||
+        if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||
                 widthMeasureSpec != mOldWidthMeasureSpec ||
                 heightMeasureSpec != mOldHeightMeasureSpec) {
 
             // first clears the measured dimension flag
-            mPrivateFlags &= ~MEASURED_DIMENSION_SET;
+            mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
 
-            if ((mPrivateFlags2 & PADDING_RESOLVED) == 0) {
+            if (!isPaddingResolved()) {
                 resolvePadding();
             }
 
@@ -14969,13 +15138,13 @@
 
             // flag not set, setMeasuredDimension() was not invoked, we raise
             // an exception to warn the developer
-            if ((mPrivateFlags & MEASURED_DIMENSION_SET) != MEASURED_DIMENSION_SET) {
+            if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) {
                 throw new IllegalStateException("onMeasure() did not set the"
                         + " measured dimension by calling"
                         + " setMeasuredDimension()");
             }
 
-            mPrivateFlags |= LAYOUT_REQUIRED;
+            mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;
         }
 
         mOldWidthMeasureSpec = widthMeasureSpec;
@@ -15049,7 +15218,7 @@
         mMeasuredWidth = measuredWidth;
         mMeasuredHeight = measuredHeight;
 
-        mPrivateFlags |= MEASURED_DIMENSION_SET;
+        mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET;
     }
 
     /**
@@ -15293,7 +15462,7 @@
      * @see #getAnimation()
      */
     protected void onAnimationStart() {
-        mPrivateFlags |= ANIMATION_STARTED;
+        mPrivateFlags |= PFLAG_ANIMATION_STARTED;
     }
 
     /**
@@ -15305,7 +15474,7 @@
      * @see #getAnimation()
      */
     protected void onAnimationEnd() {
-        mPrivateFlags &= ~ANIMATION_STARTED;
+        mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
     }
 
     /**
@@ -15342,14 +15511,14 @@
         final AttachInfo attachInfo = mAttachInfo;
         if (region != null && attachInfo != null) {
             final int pflags = mPrivateFlags;
-            if ((pflags & SKIP_DRAW) == 0) {
+            if ((pflags & PFLAG_SKIP_DRAW) == 0) {
                 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to
                 // remove it from the transparent region.
                 final int[] location = attachInfo.mTransparentLocation;
                 getLocationInWindow(location);
                 region.op(location[0], location[1], location[0] + mRight - mLeft,
                         location[1] + mBottom - mTop, Region.Op.DIFFERENCE);
-            } else if ((pflags & ONLY_DRAWS_BACKGROUND) != 0 && mBackground != null) {
+            } else if ((pflags & PFLAG_ONLY_DRAWS_BACKGROUND) != 0 && mBackground != null) {
                 // The ONLY_DRAWS_BACKGROUND flag IS set and the background drawable
                 // exists, so we remove the background drawable's non-transparent
                 // parts from this transparent region.
@@ -15826,7 +15995,7 @@
     }
 
     boolean canAcceptDrag() {
-        return (mPrivateFlags2 & DRAG_CAN_ACCEPT) != 0;
+        return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0;
     }
 
     /**
@@ -16091,7 +16260,7 @@
             @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE")
     })
     public int getTextDirection() {
-        return (mPrivateFlags2 & TEXT_DIRECTION_MASK) >> TEXT_DIRECTION_MASK_SHIFT;
+        return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT;
     }
 
     /**
@@ -16109,10 +16278,10 @@
     public void setTextDirection(int textDirection) {
         if (getTextDirection() != textDirection) {
             // Reset the current text direction and the resolved one
-            mPrivateFlags2 &= ~TEXT_DIRECTION_MASK;
+            mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK;
             resetResolvedTextDirection();
             // Set the new text direction
-            mPrivateFlags2 |= ((textDirection << TEXT_DIRECTION_MASK_SHIFT) & TEXT_DIRECTION_MASK);
+            mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK);
             // Refresh
             requestLayout();
             invalidate(true);
@@ -16137,10 +16306,10 @@
      */
     public int getResolvedTextDirection() {
         // The text direction will be resolved only if needed
-        if ((mPrivateFlags2 & TEXT_DIRECTION_RESOLVED) != TEXT_DIRECTION_RESOLVED) {
+        if ((mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) != PFLAG2_TEXT_DIRECTION_RESOLVED) {
             resolveTextDirection();
         }
-        return (mPrivateFlags2 & TEXT_DIRECTION_RESOLVED_MASK) >> TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
+        return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
     }
 
     /**
@@ -16149,7 +16318,7 @@
      */
     public void resolveTextDirection() {
         // Reset any previous text direction resolution
-        mPrivateFlags2 &= ~(TEXT_DIRECTION_RESOLVED | TEXT_DIRECTION_RESOLVED_MASK);
+        mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK);
 
         if (hasRtlSupport()) {
             // Set resolved text direction flag depending on text direction flag
@@ -16168,15 +16337,15 @@
                             case TEXT_DIRECTION_RTL:
                             case TEXT_DIRECTION_LOCALE:
                                 mPrivateFlags2 |=
-                                        (parentResolvedDirection << TEXT_DIRECTION_RESOLVED_MASK_SHIFT);
+                                        (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT);
                                 break;
                             default:
                                 // Default resolved direction is "first strong" heuristic
-                                mPrivateFlags2 |= TEXT_DIRECTION_RESOLVED_DEFAULT;
+                                mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
                         }
                     } else {
                         // We cannot do the resolution if there is no parent, so use the default one
-                        mPrivateFlags2 |= TEXT_DIRECTION_RESOLVED_DEFAULT;
+                        mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
                     }
                     break;
                 case TEXT_DIRECTION_FIRST_STRONG:
@@ -16185,19 +16354,19 @@
                 case TEXT_DIRECTION_RTL:
                 case TEXT_DIRECTION_LOCALE:
                     // Resolved direction is the same as text direction
-                    mPrivateFlags2 |= (textDirection << TEXT_DIRECTION_RESOLVED_MASK_SHIFT);
+                    mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT);
                     break;
                 default:
                     // Default resolved direction is "first strong" heuristic
-                    mPrivateFlags2 |= TEXT_DIRECTION_RESOLVED_DEFAULT;
+                    mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
             }
         } else {
             // Default resolved direction is "first strong" heuristic
-            mPrivateFlags2 |= TEXT_DIRECTION_RESOLVED_DEFAULT;
+            mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
         }
 
         // Set to resolved
-        mPrivateFlags2 |= TEXT_DIRECTION_RESOLVED;
+        mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED;
         onResolvedTextDirectionChanged();
     }
 
@@ -16230,7 +16399,7 @@
      * reset is done.
      */
     public void resetResolvedTextDirection() {
-        mPrivateFlags2 &= ~(TEXT_DIRECTION_RESOLVED | TEXT_DIRECTION_RESOLVED_MASK);
+        mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK);
         onResolvedTextDirectionReset();
     }
 
@@ -16266,7 +16435,7 @@
             @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
     })
     public int getTextAlignment() {
-        return (mPrivateFlags2 & TEXT_ALIGNMENT_MASK) >> TEXT_ALIGNMENT_MASK_SHIFT;
+        return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT;
     }
 
     /**
@@ -16287,10 +16456,10 @@
     public void setTextAlignment(int textAlignment) {
         if (textAlignment != getTextAlignment()) {
             // Reset the current and resolved text alignment
-            mPrivateFlags2 &= ~TEXT_ALIGNMENT_MASK;
+            mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK;
             resetResolvedTextAlignment();
             // Set the new text alignment
-            mPrivateFlags2 |= ((textAlignment << TEXT_ALIGNMENT_MASK_SHIFT) & TEXT_ALIGNMENT_MASK);
+            mPrivateFlags2 |= ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK);
             // Refresh
             requestLayout();
             invalidate(true);
@@ -16324,10 +16493,10 @@
     })
     public int getResolvedTextAlignment() {
         // If text alignment is not resolved, then resolve it
-        if ((mPrivateFlags2 & TEXT_ALIGNMENT_RESOLVED) != TEXT_ALIGNMENT_RESOLVED) {
+        if ((mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) != PFLAG2_TEXT_ALIGNMENT_RESOLVED) {
             resolveTextAlignment();
         }
-        return (mPrivateFlags2 & TEXT_ALIGNMENT_RESOLVED_MASK) >> TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
+        return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
     }
 
     /**
@@ -16336,7 +16505,7 @@
      */
     public void resolveTextAlignment() {
         // Reset any previous text alignment resolution
-        mPrivateFlags2 &= ~(TEXT_ALIGNMENT_RESOLVED | TEXT_ALIGNMENT_RESOLVED_MASK);
+        mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK);
 
         if (hasRtlSupport()) {
             // Set resolved text alignment flag depending on text alignment flag
@@ -16358,16 +16527,16 @@
                                 // Resolved text alignment is the same as the parent resolved
                                 // text alignment
                                 mPrivateFlags2 |=
-                                        (parentResolvedTextAlignment << TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT);
+                                        (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT);
                                 break;
                             default:
                                 // Use default resolved text alignment
-                                mPrivateFlags2 |= TEXT_ALIGNMENT_RESOLVED_DEFAULT;
+                                mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
                         }
                     }
                     else {
                         // We cannot do the resolution if there is no parent so use the default
-                        mPrivateFlags2 |= TEXT_ALIGNMENT_RESOLVED_DEFAULT;
+                        mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
                     }
                     break;
                 case TEXT_ALIGNMENT_GRAVITY:
@@ -16377,19 +16546,19 @@
                 case TEXT_ALIGNMENT_VIEW_START:
                 case TEXT_ALIGNMENT_VIEW_END:
                     // Resolved text alignment is the same as text alignment
-                    mPrivateFlags2 |= (textAlignment << TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT);
+                    mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT);
                     break;
                 default:
                     // Use default resolved text alignment
-                    mPrivateFlags2 |= TEXT_ALIGNMENT_RESOLVED_DEFAULT;
+                    mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
             }
         } else {
             // Use default resolved text alignment
-            mPrivateFlags2 |= TEXT_ALIGNMENT_RESOLVED_DEFAULT;
+            mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
         }
 
         // Set the resolved
-        mPrivateFlags2 |= TEXT_ALIGNMENT_RESOLVED;
+        mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED;
         onResolvedTextAlignmentChanged();
     }
 
@@ -16423,7 +16592,7 @@
      */
     public void resetResolvedTextAlignment() {
         // Reset any previous text alignment resolution
-        mPrivateFlags2 &= ~(TEXT_ALIGNMENT_RESOLVED | TEXT_ALIGNMENT_RESOLVED_MASK);
+        mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK);
         onResolvedTextAlignmentReset();
     }
 
@@ -16753,7 +16922,7 @@
 
     private final class CheckForTap implements Runnable {
         public void run() {
-            mPrivateFlags &= ~PREPRESSED;
+            mPrivateFlags &= ~PFLAG_PREPRESSED;
             setPressed(true);
             checkForLongClick(ViewConfiguration.getTapTimeout());
         }
@@ -17101,6 +17270,8 @@
 
         final IBinder mWindowToken;
 
+        final Display mDisplay;
+
         final Callbacks mRootCallbacks;
 
         HardwareCanvas mHardwareCanvas;
@@ -17360,11 +17531,12 @@
          *
          * @param handler the events handler the view must use
          */
-        AttachInfo(IWindowSession session, IWindow window,
+        AttachInfo(IWindowSession session, IWindow window, Display display,
                 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) {
             mSession = session;
             mWindow = window;
             mWindowToken = window.asBinder();
+            mDisplay = display;
             mViewRootImpl = viewRootImpl;
             mHandler = handler;
             mRootCallbacks = effectPlayer;
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 3082976..499075e 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -279,7 +279,8 @@
         mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
 
         // Size of the screen in bytes, in ARGB_8888 format
-        final Display display = WindowManagerImpl.getDefault().getDefaultDisplay();
+        final WindowManager win = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
+        final Display display = win.getDefaultDisplay();
         final Point size = new Point();
         display.getRealSize(size);
         mMaximumDrawingCacheSize = 4 * size.x * size.y;
@@ -288,7 +289,7 @@
         mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f);
 
         if (!sHasPermanentMenuKeySet) {
-            IWindowManager wm = WindowManagerImpl.getWindowManagerService();
+            IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
             try {
                 sHasPermanentMenuKey = !wm.hasSystemNavBar() && !wm.hasNavigationBar();
                 sHasPermanentMenuKeySet = true;
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index dae9265..1286eb9 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -497,8 +497,8 @@
             throws IOException {
 
         long durationMeasure =
-                (root || (view.mPrivateFlags & View.MEASURED_DIMENSION_SET) != 0) ? profileViewOperation(
-                        view, new ViewOperation<Void>() {
+                (root || (view.mPrivateFlags & View.PFLAG_MEASURED_DIMENSION_SET) != 0)
+                ? profileViewOperation(view, new ViewOperation<Void>() {
                             public Void[] pre() {
                                 forceLayout(view);
                                 return null;
@@ -524,8 +524,8 @@
                         })
                         : 0;
         long durationLayout =
-                (root || (view.mPrivateFlags & View.LAYOUT_REQUIRED) != 0) ? profileViewOperation(
-                        view, new ViewOperation<Void>() {
+                (root || (view.mPrivateFlags & View.PFLAG_LAYOUT_REQUIRED) != 0)
+                ? profileViewOperation(view, new ViewOperation<Void>() {
                             public Void[] pre() {
                                 return null;
                             }
@@ -538,9 +538,8 @@
                             }
                         }) : 0;
         long durationDraw =
-                (root || !view.willNotDraw() || (view.mPrivateFlags & View.DRAWN) != 0) ? profileViewOperation(
-                        view,
-                        new ViewOperation<Object>() {
+                (root || !view.willNotDraw() || (view.mPrivateFlags & View.PFLAG_DRAWN) != 0)
+                ? profileViewOperation(view, new ViewOperation<Object>() {
                             public Object[] pre() {
                                 final DisplayMetrics metrics =
                                         (view != null && view.getResources() != null) ?
@@ -651,7 +650,7 @@
 
         final boolean localVisible = view.getVisibility() == View.VISIBLE && visible;
 
-        if ((view.mPrivateFlags & View.SKIP_DRAW) != View.SKIP_DRAW) {
+        if ((view.mPrivateFlags & View.PFLAG_SKIP_DRAW) != View.PFLAG_SKIP_DRAW) {
             final int id = view.getId();
             String name = view.getClass().getSimpleName();
             if (id != View.NO_ID) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1548743..3ab0e94 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -804,7 +804,7 @@
      */
     @Override
     public boolean hasFocus() {
-        return (mPrivateFlags & FOCUSED) != 0 || mFocused != null;
+        return (mPrivateFlags & PFLAG_FOCUSED) != 0 || mFocused != null;
     }
 
     /*
@@ -898,7 +898,7 @@
         for (int i = 0; i < childrenCount; i++) {
             View child = children[i];
             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
-                    && (child.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
+                    && (child.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
                 child.findViewsWithText(outViews, text, flags);
             }
         }
@@ -1177,7 +1177,7 @@
                     final View view = mCurrentDragView;
                     event.mAction = DragEvent.ACTION_DRAG_EXITED;
                     view.dispatchDragEvent(event);
-                    view.mPrivateFlags2 &= ~View.DRAG_HOVERED;
+                    view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
                     view.refreshDrawableState();
                 }
                 mCurrentDragView = target;
@@ -1186,7 +1186,7 @@
                 if (target != null) {
                     event.mAction = DragEvent.ACTION_DRAG_ENTERED;
                     target.dispatchDragEvent(event);
-                    target.mPrivateFlags2 |= View.DRAG_HOVERED;
+                    target.mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
                     target.refreshDrawableState();
                 }
                 event.mAction = action;  // restore the event's original state
@@ -1220,7 +1220,7 @@
             if (mCurrentDragView != null) {
                 final View view = mCurrentDragView;
                 view.dispatchDragEvent(event);
-                view.mPrivateFlags2 &= ~View.DRAG_HOVERED;
+                view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
                 view.refreshDrawableState();
 
                 mCurrentDragView = null;
@@ -1281,7 +1281,7 @@
             mDragNotifiedChildren.add(child);
             canAccept = child.dispatchDragEvent(mCurrentDrag);
             if (canAccept && !child.canAcceptDrag()) {
-                child.mPrivateFlags2 |= View.DRAG_CAN_ACCEPT;
+                child.mPrivateFlags2 |= View.PFLAG2_DRAG_CAN_ACCEPT;
                 child.refreshDrawableState();
             }
         }
@@ -1330,9 +1330,11 @@
      */
     @Override
     public boolean dispatchKeyEventPreIme(KeyEvent event) {
-        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
+        if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
+                == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
             return super.dispatchKeyEventPreIme(event);
-        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
+        } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
+                == PFLAG_HAS_BOUNDS) {
             return mFocused.dispatchKeyEventPreIme(event);
         }
         return false;
@@ -1347,11 +1349,13 @@
             mInputEventConsistencyVerifier.onKeyEvent(event, 1);
         }
 
-        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
+        if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
+                == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
             if (super.dispatchKeyEvent(event)) {
                 return true;
             }
-        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
+        } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
+                == PFLAG_HAS_BOUNDS) {
             if (mFocused.dispatchKeyEvent(event)) {
                 return true;
             }
@@ -1368,9 +1372,11 @@
      */
     @Override
     public boolean dispatchKeyShortcutEvent(KeyEvent event) {
-        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
+        if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
+                == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
             return super.dispatchKeyShortcutEvent(event);
-        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
+        } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
+                == PFLAG_HAS_BOUNDS) {
             return mFocused.dispatchKeyShortcutEvent(event);
         }
         return false;
@@ -1385,11 +1391,13 @@
             mInputEventConsistencyVerifier.onTrackballEvent(event, 1);
         }
 
-        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
+        if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
+                == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
             if (super.dispatchTrackballEvent(event)) {
                 return true;
             }
-        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
+        } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
+                == PFLAG_HAS_BOUNDS) {
             if (mFocused.dispatchTrackballEvent(event)) {
                 return true;
             }
@@ -1715,8 +1723,10 @@
             final float x = event.getX();
             final float y = event.getY();
 
+            final boolean customOrder = isChildrenDrawingOrderEnabled();
             for (int i = childrenCount - 1; i >= 0; i--) {
-                final View child = children[i];
+                final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
+                final View child = children[childIndex];
                 if (!canViewReceivePointerEvents(child)
                         || !isTransformedTouchPointInView(x, y, child, null)) {
                     continue;
@@ -1738,9 +1748,11 @@
     @Override
     protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
         // Send the event to the focused child or to this view group if it has focus.
-        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
+        if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
+                == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
             return super.dispatchGenericFocusedEvent(event);
-        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
+        } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
+                == PFLAG_HAS_BOUNDS) {
             return mFocused.dispatchGenericMotionEvent(event);
         }
         return false;
@@ -1841,8 +1853,11 @@
                         final float x = ev.getX(actionIndex);
                         final float y = ev.getY(actionIndex);
 
+                        final boolean customOrder = isChildrenDrawingOrderEnabled();
                         for (int i = childrenCount - 1; i >= 0; i--) {
-                            final View child = children[i];
+                            final int childIndex = customOrder ?
+                                    getChildDrawingOrder(childrenCount, i) : i;
+                            final View child = children[childIndex];
                             if (!canViewReceivePointerEvents(child)
                                     || !isTransformedTouchPointInView(x, y, child, null)) {
                                 continue;
@@ -1860,7 +1875,7 @@
                             if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
                                 // Child wants to receive touch within its bounds.
                                 mLastTouchDownTime = ev.getDownTime();
-                                mLastTouchDownIndex = i;
+                                mLastTouchDownIndex = childIndex;
                                 mLastTouchDownX = ev.getX();
                                 mLastTouchDownY = ev.getY();
                                 newTouchTarget = addTouchTarget(child, idBitsToAssign);
@@ -1951,8 +1966,8 @@
      * Returns true if the flag was previously set.
      */
     private static boolean resetCancelNextUpFlag(View view) {
-        if ((view.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
-            view.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
+        if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
+            view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
             return true;
         }
         return false;
@@ -2517,8 +2532,11 @@
         super.dispatchDetachedFromWindow();
     }
 
+    /**
+     * @hide
+     */
     @Override
-    void internalSetPadding(int left, int top, int right, int bottom) {
+    protected void internalSetPadding(int left, int top, int right, int bottom) {
         super.internalSetPadding(left, top, right, bottom);
 
         if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
@@ -2766,7 +2784,7 @@
         }
 
         // We will draw our child's animation, let's reset the flag
-        mPrivateFlags &= ~DRAW_ANIMATION;
+        mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
         mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
 
         boolean more = false;
@@ -2886,8 +2904,9 @@
             final View child = children[i];
             if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) &&
                     child.hasStaticLayer()) {
-                child.mRecreateDisplayList = (child.mPrivateFlags & INVALIDATED) == INVALIDATED;
-                child.mPrivateFlags &= ~INVALIDATED;
+                child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED)
+                        == PFLAG_INVALIDATED;
+                child.mPrivateFlags &= ~PFLAG_INVALIDATED;
                 child.getDisplayList();
                 child.mRecreateDisplayList = false;
             }
@@ -3030,7 +3049,7 @@
         for (int i = 0; i < len; i++) {
             View v = where[i];
 
-            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
+            if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
                 v = v.findViewById(id);
 
                 if (v != null) {
@@ -3057,7 +3076,7 @@
         for (int i = 0; i < len; i++) {
             View v = where[i];
 
-            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
+            if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
                 v = v.findViewWithTag(tag);
 
                 if (v != null) {
@@ -3084,7 +3103,7 @@
         for (int i = 0; i < len; i++) {
             View v = where[i];
 
-            if (v != childToSkip && (v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
+            if (v != childToSkip && (v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
                 v = v.findViewByPredicate(predicate);
 
                 if (v != null) {
@@ -3294,7 +3313,7 @@
             boolean preventRequestLayout) {
         child.mParent = null;
         addViewInner(child, index, params, preventRequestLayout);
-        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
+        child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
         return true;
     }
 
@@ -3304,7 +3323,7 @@
      * @param child the child on which to perform the cleanup
      */
     protected void cleanupLayoutState(View child) {
-        child.mPrivateFlags &= ~View.FORCE_LAYOUT;
+        child.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
     }
 
     private void addViewInner(View child, int index, LayoutParams params,
@@ -3372,6 +3391,11 @@
         if (child.hasTransientState()) {
             childHasTransientStateChanged(child, true);
         }
+
+        if (child.getLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) {
+            child.resetResolvedLayoutDirection();
+            child.resolveRtlProperties();
+        }
     }
 
     private void addInArray(View child, int index) {
@@ -3597,6 +3621,8 @@
             childHasTransientStateChanged(view, false);
         }
 
+        view.resetResolvedLayoutDirection();
+
         onViewRemoved(view);
 
         needGlobalAttributesUpdate(false);
@@ -3844,9 +3870,10 @@
         addInArray(child, index);
 
         child.mParent = this;
-        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK & ~DRAWING_CACHE_VALID) |
-                DRAWN | INVALIDATED;
-        this.mPrivateFlags |= INVALIDATED;
+        child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK
+                        & ~PFLAG_DRAWING_CACHE_VALID)
+                | PFLAG_DRAWN | PFLAG_INVALIDATED;
+        this.mPrivateFlags |= PFLAG_INVALIDATED;
 
         if (child.hasFocus()) {
             requestChildFocus(child, child.findFocus());
@@ -3947,7 +3974,8 @@
             // If the child is drawing an animation, we want to copy this flag onto
             // ourselves and the parent to make sure the invalidate request goes
             // through
-            final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
+            final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION)
+                    == PFLAG_DRAW_ANIMATION;
 
             // Check whether the child that requests the invalidate is fully opaque
             // Views being animated or transformed are not considered opaque because we may
@@ -3957,11 +3985,11 @@
                     child.getAnimation() == null && childMatrix.isIdentity();
             // Mark the child as dirty, using the appropriate flag
             // Make sure we do not set both flags at the same time
-            int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
+            int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
 
             if (child.mLayerType != LAYER_TYPE_NONE) {
-                mPrivateFlags |= INVALIDATED;
-                mPrivateFlags &= ~DRAWING_CACHE_VALID;
+                mPrivateFlags |= PFLAG_INVALIDATED;
+                mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
                 child.mLocalDirtyRect.union(dirty);
             }
 
@@ -4003,7 +4031,7 @@
 
                 if (drawAnimation) {
                     if (view != null) {
-                        view.mPrivateFlags |= DRAW_ANIMATION;
+                        view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
                     } else if (parent instanceof ViewRootImpl) {
                         ((ViewRootImpl) parent).mIsAnimating = true;
                     }
@@ -4014,10 +4042,10 @@
                 if (view != null) {
                     if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
                             view.getSolidColor() == 0) {
-                        opaqueFlag = DIRTY;
+                        opaqueFlag = PFLAG_DIRTY;
                     }
-                    if ((view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
-                        view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
+                    if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
+                        view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;
                     }
                 }
 
@@ -4048,8 +4076,8 @@
      * does not intersect with this ViewGroup's bounds.
      */
     public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
-        if ((mPrivateFlags & DRAWN) == DRAWN ||
-                (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
+        if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
+                (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
             if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
                         FLAG_OPTIMIZE_INVALIDATE) {
                 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
@@ -4063,20 +4091,20 @@
                         dirty.setEmpty();
                     }
                 }
-                mPrivateFlags &= ~DRAWING_CACHE_VALID;
+                mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
 
                 location[CHILD_LEFT_INDEX] = left;
                 location[CHILD_TOP_INDEX] = top;
 
                 if (mLayerType != LAYER_TYPE_NONE) {
-                    mPrivateFlags |= INVALIDATED;
+                    mPrivateFlags |= PFLAG_INVALIDATED;
                     mLocalDirtyRect.union(dirty);
                 }
 
                 return mParent;
 
             } else {
-                mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
+                mPrivateFlags &= ~PFLAG_DRAWN & ~PFLAG_DRAWING_CACHE_VALID;
 
                 location[CHILD_LEFT_INDEX] = mLeft;
                 location[CHILD_TOP_INDEX] = mTop;
@@ -4088,7 +4116,7 @@
                 }
 
                 if (mLayerType != LAYER_TYPE_NONE) {
-                    mPrivateFlags |= INVALIDATED;
+                    mPrivateFlags |= PFLAG_INVALIDATED;
                     mLocalDirtyRect.union(dirty);
                 }
 
@@ -4150,8 +4178,8 @@
      * coordinate system, pruning the invalidation if the parent has already been invalidated.
      */
     private ViewParent invalidateChildInParentFast(int left, int top, final Rect dirty) {
-        if ((mPrivateFlags & DRAWN) == DRAWN ||
-                (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
+        if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
+                (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
             dirty.offset(left - mScrollX, top - mScrollY);
 
             if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0 ||
@@ -4914,11 +4942,11 @@
             view.clearAnimation();
         }
 
-        if ((view.mPrivateFlags & ANIMATION_STARTED) == ANIMATION_STARTED) {
+        if ((view.mPrivateFlags & PFLAG_ANIMATION_STARTED) == PFLAG_ANIMATION_STARTED) {
             view.onAnimationEnd();
             // Should be performed by onAnimationEnd() but this avoid an infinite loop,
             // so we'd rather be safe than sorry
-            view.mPrivateFlags &= ~ANIMATION_STARTED;
+            view.mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
             // Draw one more frame after the animation is done
             mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
         }
@@ -5017,7 +5045,7 @@
     @Override
     public boolean gatherTransparentRegion(Region region) {
         // If no transparent regions requested, we are always opaque.
-        final boolean meOpaque = (mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) == 0;
+        final boolean meOpaque = (mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0;
         if (meOpaque && region == null) {
             // The caller doesn't care about the region, so stop now.
             return true;
@@ -5042,7 +5070,7 @@
      */
     public void requestTransparentRegion(View child) {
         if (child != null) {
-            child.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
+            child.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
             if (mParent != null) {
                 mParent.requestTransparentRegion(this);
             }
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index ce6f4c5..d8db14c 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -1036,7 +1036,7 @@
             if ((propertyMask & TRANSFORM_MASK) != 0) {
                 mView.mTransformationInfo.mMatrixDirty = true;
                 if (!useDisplayListProperties) {
-                    mView.mPrivateFlags |= View.DRAWN; // force another invalidation
+                    mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation
                 }
             }
             // invalidate(false) in all cases except if alphaHandled gets set to true
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index afcbaaf..725d9b5 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -18,7 +18,6 @@
 
 import android.Manifest;
 import android.animation.LayoutTransition;
-import android.animation.ValueAnimator;
 import android.app.ActivityManagerNative;
 import android.content.ClipDescription;
 import android.content.ComponentCallbacks;
@@ -88,7 +87,7 @@
 /**
  * The top of a view hierarchy, implementing the needed protocol between View
  * and the WindowManager.  This is for the most part an internal implementation
- * detail of {@link WindowManagerImpl}.
+ * detail of {@link WindowManagerGlobal}.
  *
  * {@hide}
  */
@@ -126,11 +125,6 @@
      */
     static final int MAX_TRACKBALL_DELAY = 250;
 
-    static IWindowSession sWindowSession;
-
-    static final Object mStaticInit = new Object();
-    static boolean mInitialized = false;
-
     static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
 
     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
@@ -143,6 +137,9 @@
     private static boolean sRenderThreadQueried = false;
     private static final Object[] sRenderThreadQueryLock = new Object[0];
 
+    final IWindowSession mWindowSession;
+    final Display mDisplay;
+
     long mLastTrackballTime = 0;
     final TrackballAxis mTrackballAxisX = new TrackballAxis();
     final TrackballAxis mTrackballAxisY = new TrackballAxis();
@@ -250,7 +247,7 @@
     boolean mAdded;
     boolean mAddedTouchMode;
 
-    CompatibilityInfoHolder mCompatibilityInfo;
+    final CompatibilityInfoHolder mCompatibilityInfo;
 
     // These are accessed by multiple threads.
     final Rect mWinFrame; // frame given by window manager.
@@ -322,24 +319,6 @@
             InputEventConsistencyVerifier.isInstrumentationEnabled() ?
                     new InputEventConsistencyVerifier(this, 0) : null;
 
-    public static IWindowSession getWindowSession(Looper mainLooper) {
-        synchronized (mStaticInit) {
-            if (!mInitialized) {
-                try {
-                    InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
-                    IWindowManager windowManager = WindowManagerImpl.getWindowManagerService();
-                    sWindowSession = windowManager.openSession(
-                            imm.getClient(), imm.getInputContext());
-                    float animatorScale = windowManager.getAnimationScale(2);
-                    ValueAnimator.setDurationScale(animatorScale);
-                    mInitialized = true;
-                } catch (RemoteException e) {
-                }
-            }
-            return sWindowSession;
-        }
-    }
-
     static final class SystemUiVisibilityInfo {
         int seq;
         int globalVisibility;
@@ -347,7 +326,7 @@
         int localChanges;
     }
     
-    public ViewRootImpl(Context context) {
+    public ViewRootImpl(Context context, Display display) {
         super();
 
         if (MEASURE_LATENCY) {
@@ -359,7 +338,11 @@
         // Initialize the statics when this class is first instantiated. This is
         // done here instead of in the static block because Zygote does not
         // allow the spawning of threads.
-        getWindowSession(context.getMainLooper());
+        mWindowSession = WindowManagerGlobal.getWindowSession(context.getMainLooper());
+        mDisplay = display;
+
+        CompatibilityInfoHolder cih = display.getCompatibilityInfo();
+        mCompatibilityInfo = cih != null ? cih : new CompatibilityInfoHolder();
 
         mThread = Thread.currentThread();
         mLocation = new WindowLeaked(null);
@@ -383,7 +366,7 @@
             new AccessibilityInteractionConnectionManager();
         mAccessibilityManager.addAccessibilityStateChangeListener(
                 mAccessibilityInteractionConnectionManager);
-        mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, mHandler, this);
+        mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);
         mViewConfiguration = ViewConfiguration.get(context);
         mDensity = context.getResources().getDisplayMetrics().densityDpi;
         mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
@@ -460,9 +443,10 @@
      * @hide
      */
     static boolean isInTouchMode() {
-        if (mInitialized) {
+        IWindowSession windowSession = WindowManagerGlobal.peekWindowSession();
+        if (windowSession != null) {
             try {
-                return sWindowSession.getInTouchMode();
+                return windowSession.getInTouchMode();
             } catch (RemoteException e) {
             }
         }
@@ -541,8 +525,8 @@
                     mOrigWindowType = mWindowAttributes.type;
                     mAttachInfo.mRecomputeGlobalAttributes = true;
                     collectViewAttributes();
-                    res = sWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
-                            getHostVisibility(), Display.DEFAULT_DISPLAY,
+                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
+                            getHostVisibility(), mDisplay.getDisplayId(),
                             mAttachInfo.mContentInsets, mInputChannel);
                 } catch (RemoteException e) {
                     mAdded = false;
@@ -565,7 +549,7 @@
                 mPendingContentInsets.set(mAttachInfo.mContentInsets);
                 mPendingVisibleInsets.set(0, 0, 0, 0);
                 if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
-                if (res < WindowManagerImpl.ADD_OKAY) {
+                if (res < WindowManagerGlobal.ADD_OKAY) {
                     mView = null;
                     mAttachInfo.mRootView = null;
                     mAdded = false;
@@ -573,33 +557,33 @@
                     unscheduleTraversals();
                     setAccessibilityFocus(null, null);
                     switch (res) {
-                        case WindowManagerImpl.ADD_BAD_APP_TOKEN:
-                        case WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN:
-                            throw new WindowManagerImpl.BadTokenException(
+                        case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
+                        case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
+                            throw new WindowManager.BadTokenException(
                                 "Unable to add window -- token " + attrs.token
                                 + " is not valid; is your activity running?");
-                        case WindowManagerImpl.ADD_NOT_APP_TOKEN:
-                            throw new WindowManagerImpl.BadTokenException(
+                        case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
+                            throw new WindowManager.BadTokenException(
                                 "Unable to add window -- token " + attrs.token
                                 + " is not for an application");
-                        case WindowManagerImpl.ADD_APP_EXITING:
-                            throw new WindowManagerImpl.BadTokenException(
+                        case WindowManagerGlobal.ADD_APP_EXITING:
+                            throw new WindowManager.BadTokenException(
                                 "Unable to add window -- app for token " + attrs.token
                                 + " is exiting");
-                        case WindowManagerImpl.ADD_DUPLICATE_ADD:
-                            throw new WindowManagerImpl.BadTokenException(
+                        case WindowManagerGlobal.ADD_DUPLICATE_ADD:
+                            throw new WindowManager.BadTokenException(
                                 "Unable to add window -- window " + mWindow
                                 + " has already been added");
-                        case WindowManagerImpl.ADD_STARTING_NOT_NEEDED:
+                        case WindowManagerGlobal.ADD_STARTING_NOT_NEEDED:
                             // Silently ignore -- we would have just removed it
                             // right away, anyway.
                             return;
-                        case WindowManagerImpl.ADD_MULTIPLE_SINGLETON:
-                            throw new WindowManagerImpl.BadTokenException(
+                        case WindowManagerGlobal.ADD_MULTIPLE_SINGLETON:
+                            throw new WindowManager.BadTokenException(
                                 "Unable to add window " + mWindow +
                                 " -- another window of this type already exists");
-                        case WindowManagerImpl.ADD_PERMISSION_DENIED:
-                            throw new WindowManagerImpl.BadTokenException(
+                        case WindowManagerGlobal.ADD_PERMISSION_DENIED:
+                            throw new WindowManager.BadTokenException(
                                 "Unable to add window " + mWindow +
                                 " -- permission denied for this window type");
                     }
@@ -622,8 +606,8 @@
                 }
 
                 view.assignParent(this);
-                mAddedTouchMode = (res&WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE) != 0;
-                mAppVisible = (res&WindowManagerImpl.ADD_FLAG_APP_VISIBLE) != 0;
+                mAddedTouchMode = (res & WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE) != 0;
+                mAppVisible = (res & WindowManagerGlobal.ADD_FLAG_APP_VISIBLE) != 0;
 
                 if (mAccessibilityManager.isEnabled()) {
                     mAccessibilityInteractionConnectionManager.ensureConnection();
@@ -1164,9 +1148,8 @@
 
             if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
                 // NOTE -- system code, won't try to do compat mode.
-                Display disp = WindowManagerImpl.getDefault().getDefaultDisplay();
                 Point size = new Point();
-                disp.getRealSize(size);
+                mDisplay.getRealSize(size);
                 desiredWindowWidth = size.x;
                 desiredWindowHeight = size.y;
             } else {
@@ -1251,9 +1234,8 @@
 
                     if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL) {
                         // NOTE -- system code, won't try to do compat mode.
-                        Display disp = WindowManagerImpl.getDefault().getDefaultDisplay();
                         Point size = new Point();
-                        disp.getRealSize(size);
+                        mDisplay.getRealSize(size);
                         desiredWindowWidth = size.x;
                         desiredWindowHeight = size.y;
                     } else {
@@ -1303,7 +1285,7 @@
             }
         }
 
-        if (params != null && (host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
+        if (params != null && (host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
             if (!PixelFormat.formatHasAlpha(params.format)) {
                 params.format = PixelFormat.TRANSLUCENT;
             }
@@ -1502,7 +1484,7 @@
                             } catch (Surface.OutOfResourcesException e) {
                                 Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
                                 try {
-                                    if (!sWindowSession.outOfMemory(mWindow)) {
+                                    if (!mWindowSession.outOfMemory(mWindow)) {
                                         Slog.w(TAG, "No processes killed for memory; killing self");
                                         Process.killProcess(Process.myPid());
                                     }
@@ -1535,7 +1517,7 @@
                     } catch (Surface.OutOfResourcesException e) {
                         Log.e(TAG, "OutOfResourcesException updating HW surface", e);
                         try {
-                            if (!sWindowSession.outOfMemory(mWindow)) {
+                            if (!mWindowSession.outOfMemory(mWindow)) {
                                 Slog.w(TAG, "No processes killed for memory; killing self");
                                 Process.killProcess(Process.myPid());
                             }
@@ -1629,7 +1611,7 @@
 
             if (!mStopped) {
                 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
-                        (relayoutResult&WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
+                        (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
                 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
                         || mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
                     int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
@@ -1709,7 +1691,7 @@
             // By this point all views have been sized and positionned
             // We can compute the transparent area
 
-            if ((host.mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) != 0) {
+            if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
                 // start out transparent
                 // TODO: AVOID THAT CALL BY CACHING THE RESULT?
                 host.getLocationInWindow(mTmpLocation);
@@ -1726,7 +1708,7 @@
                     mPreviousTransparentRegion.set(mTransparentRegion);
                     // reconfigure window manager
                     try {
-                        sWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
+                        mWindowSession.setTransparentRegion(mWindow, mTransparentRegion);
                     } catch (RemoteException e) {
                     }
                 }
@@ -1775,7 +1757,7 @@
                 }
 
                 try {
-                    sWindowSession.setInsets(mWindow, insets.mTouchableInsets,
+                    mWindowSession.setInsets(mWindow, insets.mTouchableInsets,
                             contentInsets, visibleInsets, touchableRegion);
                 } catch (RemoteException e) {
                 }
@@ -1800,7 +1782,7 @@
                             + mRealFocusedView);
                 }
             }
-            if ((relayoutResult&WindowManagerImpl.RELAYOUT_RES_ANIMATING) != 0) {
+            if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_ANIMATING) != 0) {
                 // The first time we relayout the window, if the system is
                 // doing window animations, we want to hold of on any future
                 // draws until the animation is done.
@@ -1831,7 +1813,7 @@
         }
 
         // Remember if we must report the next draw.
-        if ((relayoutResult & WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) {
+        if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
             mReportNextDraw = true;
         }
 
@@ -1893,7 +1875,7 @@
         // the test below should not fail unless someone is messing with us
         checkThread();
         if (mView == child) {
-            mView.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
+            mView.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
             // Need to make sure we re-evaluate the window attributes next
             // time around, to ensure the window has the correct format.
             mWindowAttributesChanged = true;
@@ -2061,7 +2043,7 @@
                 }
             }
             try {
-                sWindowSession.finishDrawing(mWindow);
+                mWindowSession.finishDrawing(mWindow);
             } catch (RemoteException e) {
             }
         }
@@ -2217,7 +2199,7 @@
         } catch (Surface.OutOfResourcesException e) {
             Log.e(TAG, "OutOfResourcesException locking surface", e);
             try {
-                if (!sWindowSession.outOfMemory(mWindow)) {
+                if (!mWindowSession.outOfMemory(mWindow)) {
                     Slog.w(TAG, "No processes killed for memory; killing self");
                     Process.killProcess(Process.myPid());
                 }
@@ -2256,7 +2238,7 @@
             dirty.setEmpty();
             mIsAnimating = false;
             attachInfo.mDrawingTime = SystemClock.uptimeMillis();
-            mView.mPrivateFlags |= View.DRAWN;
+            mView.mPrivateFlags |= View.PFLAG_DRAWN;
 
             if (DEBUG_DRAW) {
                 Context cxt = mView.getContext();
@@ -2646,7 +2628,7 @@
             mInputEventReceiver = null;
         }
         try {
-            sWindowSession.remove(mWindow);
+            mWindowSession.remove(mWindow);
         } catch (RemoteException e) {
         }
         
@@ -2891,7 +2873,7 @@
                             } catch (Surface.OutOfResourcesException e) {
                                 Log.e(TAG, "OutOfResourcesException locking surface", e);
                                 try {
-                                    if (!sWindowSession.outOfMemory(mWindow)) {
+                                    if (!mWindowSession.outOfMemory(mWindow)) {
                                         Slog.w(TAG, "No processes killed for memory; killing self");
                                         Process.killProcess(Process.myPid());
                                     }
@@ -3036,7 +3018,7 @@
 
         // tell the window manager
         try {
-            sWindowSession.setInTouchMode(inTouchMode);
+            mWindowSession.setInTouchMode(inTouchMode);
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
@@ -3750,10 +3732,10 @@
                 if (prevDragView != mCurrentDragView) {
                     try {
                         if (prevDragView != null) {
-                            sWindowSession.dragRecipientExited(mWindow);
+                            mWindowSession.dragRecipientExited(mWindow);
                         }
                         if (mCurrentDragView != null) {
-                            sWindowSession.dragRecipientEntered(mWindow);
+                            mWindowSession.dragRecipientEntered(mWindow);
                         }
                     } catch (RemoteException e) {
                         Slog.e(TAG, "Unable to note drag target change");
@@ -3765,7 +3747,7 @@
                     mDragDescription = null;
                     try {
                         Log.i(TAG, "Reporting drop result: " + result);
-                        sWindowSession.reportDropResult(mWindow, result);
+                        mWindowSession.reportDropResult(mWindow, result);
                     } catch (RemoteException e) {
                         Log.e(TAG, "Unable to report drop result");
                     }
@@ -3867,11 +3849,11 @@
                 params.type = mOrigWindowType;
             }
         }
-        int relayoutResult = sWindowSession.relayout(
+        int relayoutResult = mWindowSession.relayout(
                 mWindow, mSeq, params,
                 (int) (mView.getMeasuredWidth() * appScale + 0.5f),
                 (int) (mView.getMeasuredHeight() * appScale + 0.5f),
-                viewVisibility, insetsPending ? WindowManagerImpl.RELAYOUT_INSETS_PENDING : 0,
+                viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
                 mWinFrame, mPendingContentInsets, mPendingVisibleInsets,
                 mPendingConfiguration, mSurface);
         //Log.d(TAG, "<<<<<< BACK FROM relayout");
@@ -3928,7 +3910,7 @@
      */
     public boolean performHapticFeedback(int effectId, boolean always) {
         try {
-            return sWindowSession.performHapticFeedback(mWindow, effectId, always);
+            return mWindowSession.performHapticFeedback(mWindow, effectId, always);
         } catch (RemoteException e) {
             return false;
         }
@@ -4007,8 +3989,8 @@
                         // animation info.
                         try {
                             if ((relayoutWindow(mWindowAttributes, viewVisibility, false)
-                                    & WindowManagerImpl.RELAYOUT_RES_FIRST_TIME) != 0) {
-                                sWindowSession.finishDrawing(mWindow);
+                                    & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
+                                mWindowSession.finishDrawing(mWindow);
                             }
                         } catch (RemoteException e) {
                         }
@@ -4726,9 +4708,11 @@
 
     static class W extends IWindow.Stub {
         private final WeakReference<ViewRootImpl> mViewAncestor;
+        private final IWindowSession mWindowSession;
 
         W(ViewRootImpl viewAncestor) {
             mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
+            mWindowSession = viewAncestor.mWindowSession;
         }
 
         public void resized(Rect frame, Rect contentInsets,
@@ -4827,7 +4811,7 @@
                 boolean sync) {
             if (sync) {
                 try {
-                    sWindowSession.wallpaperOffsetsComplete(asBinder());
+                    mWindowSession.wallpaperOffsetsComplete(asBinder());
                 } catch (RemoteException e) {
                 }
             }
@@ -4837,7 +4821,7 @@
                 int z, Bundle extras, boolean sync) {
             if (sync) {
                 try {
-                    sWindowSession.wallpaperCommandComplete(asBinder(), null);
+                    mWindowSession.wallpaperCommandComplete(asBinder(), null);
                 } catch (RemoteException e) {
                 }
             }
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index f57f056..a242895 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -16,7 +16,6 @@
 
 package android.view;
 
-import android.app.Application;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
@@ -455,7 +454,7 @@
      * display panels.  This is <em>not</em> used for displaying the
      * Window itself -- that must be done by the client.
      *
-     * @param wm The ViewManager for adding new windows.
+     * @param wm The window manager for adding new windows.
      */
     public void setWindowManager(WindowManager wm, IBinder appToken, String appName) {
         setWindowManager(wm, appToken, appName, false);
@@ -466,7 +465,7 @@
      * display panels.  This is <em>not</em> used for displaying the
      * Window itself -- that must be done by the client.
      *
-     * @param wm The ViewManager for adding new windows.
+     * @param wm The window manager for adding new windows.
      */
     public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
             boolean hardwareAccelerated) {
@@ -475,14 +474,9 @@
         mHardwareAccelerated = hardwareAccelerated
                 || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
         if (wm == null) {
-            wm = WindowManagerImpl.getDefault();
+            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
         }
-        mWindowManager = ((WindowManagerImpl)wm).makeLocal(this);
-    }
-
-    CompatibilityInfoHolder getCompatibilityInfo() {
-        Application app = (Application)mContext.getApplicationContext();
-        return app != null ? app.mLoadedApk.mCompatibilityInfo : null;
+        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
     }
 
     void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
new file mode 100644
index 0000000..7855763c
--- /dev/null
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -0,0 +1,516 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.animation.ValueAnimator;
+import android.app.ActivityManager;
+import android.content.ComponentCallbacks2;
+import android.content.res.Configuration;
+import android.opengl.ManagedEGLContext;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.util.AndroidRuntimeException;
+import android.util.Log;
+import android.view.inputmethod.InputMethodManager;
+
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+
+/**
+ * Provides low-level communication with the system window manager for
+ * operations that are not associated with any particular context.
+ *
+ * This class is only used internally to implement global functions where
+ * the caller already knows the display and relevant compatibility information
+ * for the operation.  For most purposes, you should use {@link WindowManager} instead
+ * since it is bound to a context.
+ *
+ * @see WindowManagerImpl
+ * @hide
+ */
+public final class WindowManagerGlobal {
+    private static final String TAG = "WindowManager";
+
+    /**
+     * The user is navigating with keys (not the touch screen), so
+     * navigational focus should be shown.
+     */
+    public static final int RELAYOUT_RES_IN_TOUCH_MODE = 0x1;
+
+    /**
+     * This is the first time the window is being drawn,
+     * so the client must call drawingFinished() when done
+     */
+    public static final int RELAYOUT_RES_FIRST_TIME = 0x2;
+
+    /**
+     * The window manager has changed the surface from the last call.
+     */
+    public static final int RELAYOUT_RES_SURFACE_CHANGED = 0x4;
+
+    /**
+     * The window manager is currently animating.  It will call
+     * IWindow.doneAnimating() when done.
+     */
+    public static final int RELAYOUT_RES_ANIMATING = 0x8;
+
+    /**
+     * Flag for relayout: the client will be later giving
+     * internal insets; as a result, the window will not impact other window
+     * layouts until the insets are given.
+     */
+    public static final int RELAYOUT_INSETS_PENDING = 0x1;
+
+    /**
+     * Flag for relayout: the client may be currently using the current surface,
+     * so if it is to be destroyed as a part of the relayout the destroy must
+     * be deferred until later.  The client will call performDeferredDestroy()
+     * when it is okay.
+     */
+    public static final int RELAYOUT_DEFER_SURFACE_DESTROY = 0x2;
+
+    public static final int ADD_FLAG_APP_VISIBLE = 0x2;
+    public static final int ADD_FLAG_IN_TOUCH_MODE = RELAYOUT_RES_IN_TOUCH_MODE;
+
+    public static final int ADD_OKAY = 0;
+    public static final int ADD_BAD_APP_TOKEN = -1;
+    public static final int ADD_BAD_SUBWINDOW_TOKEN = -2;
+    public static final int ADD_NOT_APP_TOKEN = -3;
+    public static final int ADD_APP_EXITING = -4;
+    public static final int ADD_DUPLICATE_ADD = -5;
+    public static final int ADD_STARTING_NOT_NEEDED = -6;
+    public static final int ADD_MULTIPLE_SINGLETON = -7;
+    public static final int ADD_PERMISSION_DENIED = -8;
+
+    private static WindowManagerGlobal sDefaultWindowManager;
+    private static IWindowManager sWindowManagerService;
+    private static IWindowSession sWindowSession;
+
+    private final Object mLock = new Object();
+
+    private View[] mViews;
+    private ViewRootImpl[] mRoots;
+    private WindowManager.LayoutParams[] mParams;
+    private boolean mNeedsEglTerminate;
+
+    private Runnable mSystemPropertyUpdater;
+
+    private WindowManagerGlobal() {
+    }
+
+    public static WindowManagerGlobal getInstance() {
+        synchronized (WindowManagerGlobal.class) {
+            if (sDefaultWindowManager == null) {
+                sDefaultWindowManager = new WindowManagerGlobal();
+            }
+            return sDefaultWindowManager;
+        }
+    }
+
+    public static IWindowManager getWindowManagerService() {
+        synchronized (WindowManagerGlobal.class) {
+            if (sWindowManagerService == null) {
+                sWindowManagerService = IWindowManager.Stub.asInterface(
+                        ServiceManager.getService("window"));
+            }
+            return sWindowManagerService;
+        }
+    }
+
+    public static IWindowSession getWindowSession(Looper mainLooper) {
+        synchronized (WindowManagerGlobal.class) {
+            if (sWindowSession == null) {
+                try {
+                    InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
+                    IWindowManager windowManager = getWindowManagerService();
+                    sWindowSession = windowManager.openSession(
+                            imm.getClient(), imm.getInputContext());
+                    float animatorScale = windowManager.getAnimationScale(2);
+                    ValueAnimator.setDurationScale(animatorScale);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to open window session", e);
+                }
+            }
+            return sWindowSession;
+        }
+    }
+
+    public static IWindowSession peekWindowSession() {
+        synchronized (WindowManagerGlobal.class) {
+            return sWindowSession;
+        }
+    }
+
+    public void addView(View view, ViewGroup.LayoutParams params,
+            Display display, Window parentWindow) {
+        if (view == null) {
+            throw new IllegalArgumentException("view must not be null");
+        }
+        if (display == null) {
+            throw new IllegalArgumentException("display must not be null");
+        }
+        if (!(params instanceof WindowManager.LayoutParams)) {
+            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
+        }
+
+        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
+        if (parentWindow != null) {
+            parentWindow.adjustLayoutParamsForSubWindow(wparams);
+        }
+
+        ViewRootImpl root;
+        View panelParentView = null;
+
+        synchronized (mLock) {
+            // Start watching for system property changes.
+            if (mSystemPropertyUpdater == null) {
+                mSystemPropertyUpdater = new Runnable() {
+                    @Override public void run() {
+                        synchronized (mLock) {
+                            for (ViewRootImpl root : mRoots) {
+                                root.loadSystemProperties();
+                            }
+                        }
+                    }
+                };
+                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
+            }
+
+            int index = findViewLocked(view, false);
+            if (index >= 0) {
+                throw new IllegalStateException("View " + view
+                        + " has already been added to the window manager.");
+            }
+
+            // If this is a panel window, then find the window it is being
+            // attached to for future reference.
+            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
+                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
+                final int count = mViews != null ? mViews.length : 0;
+                for (int i=0; i<count; i++) {
+                    if (mRoots[i].mWindow.asBinder() == wparams.token) {
+                        panelParentView = mViews[i];
+                    }
+                }
+            }
+
+            root = new ViewRootImpl(view.getContext(), display);
+
+            view.setLayoutParams(wparams);
+
+            if (mViews == null) {
+                index = 1;
+                mViews = new View[1];
+                mRoots = new ViewRootImpl[1];
+                mParams = new WindowManager.LayoutParams[1];
+            } else {
+                index = mViews.length + 1;
+                Object[] old = mViews;
+                mViews = new View[index];
+                System.arraycopy(old, 0, mViews, 0, index-1);
+                old = mRoots;
+                mRoots = new ViewRootImpl[index];
+                System.arraycopy(old, 0, mRoots, 0, index-1);
+                old = mParams;
+                mParams = new WindowManager.LayoutParams[index];
+                System.arraycopy(old, 0, mParams, 0, index-1);
+            }
+            index--;
+
+            mViews[index] = view;
+            mRoots[index] = root;
+            mParams[index] = wparams;
+        }
+
+        // do this last because it fires off messages to start doing things
+        root.setView(view, wparams, panelParentView);
+    }
+
+    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
+        if (view == null) {
+            throw new IllegalArgumentException("view must not be null");
+        }
+        if (!(params instanceof WindowManager.LayoutParams)) {
+            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
+        }
+
+        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
+
+        view.setLayoutParams(wparams);
+
+        synchronized (mLock) {
+            int index = findViewLocked(view, true);
+            ViewRootImpl root = mRoots[index];
+            mParams[index] = wparams;
+            root.setLayoutParams(wparams, false);
+        }
+    }
+
+    public void removeView(View view, boolean immediate) {
+        if (view == null) {
+            throw new IllegalArgumentException("view must not be null");
+        }
+
+        synchronized (mLock) {
+            int index = findViewLocked(view, true);
+            View curView = removeViewLocked(index, immediate);
+            if (curView == view) {
+                return;
+            }
+
+            throw new IllegalStateException("Calling with view " + view
+                    + " but the ViewAncestor is attached to " + curView);
+        }
+    }
+
+    public void closeAll(IBinder token, String who, String what) {
+        synchronized (mLock) {
+            if (mViews == null)
+                return;
+
+            int count = mViews.length;
+            //Log.i("foo", "Closing all windows of " + token);
+            for (int i=0; i<count; i++) {
+                //Log.i("foo", "@ " + i + " token " + mParams[i].token
+                //        + " view " + mRoots[i].getView());
+                if (token == null || mParams[i].token == token) {
+                    ViewRootImpl root = mRoots[i];
+
+                    //Log.i("foo", "Force closing " + root);
+                    if (who != null) {
+                        WindowLeaked leak = new WindowLeaked(
+                                what + " " + who + " has leaked window "
+                                + root.getView() + " that was originally added here");
+                        leak.setStackTrace(root.getLocation().getStackTrace());
+                        Log.e(TAG, leak.getMessage(), leak);
+                    }
+
+                    removeViewLocked(i, false);
+                    i--;
+                    count--;
+                }
+            }
+        }
+    }
+
+    private View removeViewLocked(int index, boolean immediate) {
+        ViewRootImpl root = mRoots[index];
+        View view = root.getView();
+
+        if (view != null) {
+            InputMethodManager imm = InputMethodManager.getInstance(view.getContext());
+            if (imm != null) {
+                imm.windowDismissed(mViews[index].getWindowToken());
+            }
+        }
+        root.die(immediate);
+
+        final int count = mViews.length;
+
+        // remove it from the list
+        View[] tmpViews = new View[count-1];
+        removeItem(tmpViews, mViews, index);
+        mViews = tmpViews;
+
+        ViewRootImpl[] tmpRoots = new ViewRootImpl[count-1];
+        removeItem(tmpRoots, mRoots, index);
+        mRoots = tmpRoots;
+
+        WindowManager.LayoutParams[] tmpParams
+                = new WindowManager.LayoutParams[count-1];
+        removeItem(tmpParams, mParams, index);
+        mParams = tmpParams;
+
+        if (view != null) {
+            view.assignParent(null);
+            // func doesn't allow null...  does it matter if we clear them?
+            //view.setLayoutParams(null);
+        }
+        return view;
+    }
+
+    private static void removeItem(Object[] dst, Object[] src, int index) {
+        if (dst.length > 0) {
+            if (index > 0) {
+                System.arraycopy(src, 0, dst, 0, index);
+            }
+            if (index < dst.length) {
+                System.arraycopy(src, index+1, dst, index, src.length-index-1);
+            }
+        }
+    }
+
+    private int findViewLocked(View view, boolean required) {
+        synchronized (mLock) {
+            if (mViews != null) {
+                final int count = mViews.length;
+                for (int i = 0; i < count; i++) {
+                    if (mViews[i] == view) {
+                        return i;
+                    }
+                }
+            }
+            if (required) {
+                throw new IllegalArgumentException("View not attached to window manager");
+            }
+            return -1;
+        }
+    }
+
+    public void startTrimMemory(int level) {
+        if (HardwareRenderer.isAvailable()) {
+            // On low-end gfx devices we trim when memory is moderate;
+            // on high-end devices we do this when low.
+            if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
+                    || (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE
+                            && !ActivityManager.isHighEndGfx())) {
+                // Destroy all hardware surfaces and resources associated to
+                // known windows
+                synchronized (mLock) {
+                    if (mViews == null) return;
+                    int count = mViews.length;
+                    for (int i = 0; i < count; i++) {
+                        mRoots[i].terminateHardwareResources();
+                    }
+                }
+                // Force a full memory flush
+                mNeedsEglTerminate = true;
+                HardwareRenderer.startTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
+                return;
+            }
+
+            HardwareRenderer.startTrimMemory(level);
+        }
+    }
+
+    public void endTrimMemory() {
+        HardwareRenderer.endTrimMemory();
+
+        if (mNeedsEglTerminate) {
+            ManagedEGLContext.doTerminate();
+            mNeedsEglTerminate = false;
+        }
+    }
+
+    public void trimLocalMemory() {
+        synchronized (mLock) {
+            if (mViews == null) return;
+            int count = mViews.length;
+            for (int i = 0; i < count; i++) {
+                mRoots[i].destroyHardwareLayers();
+            }
+        }
+    }
+
+    public void dumpGfxInfo(FileDescriptor fd) {
+        FileOutputStream fout = new FileOutputStream(fd);
+        PrintWriter pw = new PrintWriter(fout);
+        try {
+            synchronized (mLock) {
+                if (mViews != null) {
+                    final int count = mViews.length;
+
+                    pw.println("Profile data in ms:");
+
+                    for (int i = 0; i < count; i++) {
+                        ViewRootImpl root = mRoots[i];
+                        String name = getWindowName(root);
+                        pw.printf("\n\t%s", name);
+
+                        HardwareRenderer renderer =
+                                root.getView().mAttachInfo.mHardwareRenderer;
+                        if (renderer != null) {
+                            renderer.dumpGfxInfo(pw);
+                        }
+                    }
+
+                    pw.println("\nView hierarchy:\n");
+
+                    int viewsCount = 0;
+                    int displayListsSize = 0;
+                    int[] info = new int[2];
+
+                    for (int i = 0; i < count; i++) {
+                        ViewRootImpl root = mRoots[i];
+                        root.dumpGfxInfo(info);
+
+                        String name = getWindowName(root);
+                        pw.printf("  %s\n  %d views, %.2f kB of display lists",
+                                name, info[0], info[1] / 1024.0f);
+                        HardwareRenderer renderer =
+                                root.getView().mAttachInfo.mHardwareRenderer;
+                        if (renderer != null) {
+                            pw.printf(", %d frames rendered", renderer.getFrameCount());
+                        }
+                        pw.printf("\n\n");
+
+                        viewsCount += info[0];
+                        displayListsSize += info[1];
+                    }
+
+                    pw.printf("\nTotal ViewRootImpl: %d\n", count);
+                    pw.printf("Total Views:        %d\n", viewsCount);
+                    pw.printf("Total DisplayList:  %.2f kB\n\n", displayListsSize / 1024.0f);
+                }
+            }
+        } finally {
+            pw.flush();
+        }
+    }
+
+    private static String getWindowName(ViewRootImpl root) {
+        return root.mWindowAttributes.getTitle() + "/" +
+                root.getClass().getName() + '@' + Integer.toHexString(root.hashCode());
+    }
+
+    public void setStoppedState(IBinder token, boolean stopped) {
+        synchronized (mLock) {
+            if (mViews != null) {
+                int count = mViews.length;
+                for (int i=0; i < count; i++) {
+                    if (token == null || mParams[i].token == token) {
+                        ViewRootImpl root = mRoots[i];
+                        root.setStopped(stopped);
+                    }
+                }
+            }
+        }
+    }
+
+    public void reportNewConfiguration(Configuration config) {
+        synchronized (mLock) {
+            if (mViews != null) {
+                int count = mViews.length;
+                config = new Configuration(config);
+                for (int i=0; i < count; i++) {
+                    ViewRootImpl root = mRoots[i];
+                    root.requestUpdateConfiguration(config);
+                }
+            }
+        }
+    }
+}
+
+final class WindowLeaked extends AndroidRuntimeException {
+    public WindowLeaked(String msg) {
+        super(msg);
+    }
+}
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index bd95cdb..bf061df 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -16,34 +16,20 @@
 
 package android.view;
 
-import android.app.ActivityManager;
-import android.content.ComponentCallbacks2;
-import android.content.res.Configuration;
-import android.opengl.ManagedEGLContext;
-import android.os.IBinder;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
-import android.util.AndroidRuntimeException;
-import android.util.Log;
-import android.view.inputmethod.InputMethodManager;
-
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-
-final class WindowLeaked extends AndroidRuntimeException {
-    public WindowLeaked(String msg) {
-        super(msg);
-    }
-}
+import android.content.Context;
+import android.hardware.display.DisplayManager;
 
 /**
- * Low-level communication with the global system window manager.  It implements
- * the ViewManager interface, allowing you to add any View subclass as a
- * top-level window on the screen. Additional window manager specific layout
- * parameters are defined for control over how windows are displayed.
- * It also implements the WindowManager interface, allowing you to control the
- * displays attached to the device.
+ * Provides low-level communication with the system window manager for
+ * operations that are bound to a particular context, display or parent window.
+ * Instances of this object are sensitive to the compatibility info associated
+ * with the running application.
+ *
+ * This object implements the {@link ViewManager} interface,
+ * allowing you to add any View subclass as a top-level window on the screen.
+ * Additional window manager specific layout parameters are defined for
+ * control over how windows are displayed.  It also implements the {@link WindowManager}
+ * interface, allowing you to control the displays attached to the device.
  * 
  * <p>Applications will not normally use WindowManager directly, instead relying
  * on the higher-level facilities in {@link android.app.Activity} and
@@ -51,531 +37,58 @@
  * 
  * <p>Even for low-level window manager access, it is almost never correct to use
  * this class.  For example, {@link android.app.Activity#getWindowManager}
- * provides a ViewManager for adding windows that are associated with that
+ * provides a window manager for adding windows that are associated with that
  * activity -- the window manager will not normally allow you to add arbitrary
  * windows that are not associated with an activity.
- * 
+ *
+ * @see WindowManager
+ * @see WindowManagerGlobal
  * @hide
  */
-public class WindowManagerImpl implements WindowManager {
-    private static final String TAG = "WindowManager";
-
-    /**
-     * The user is navigating with keys (not the touch screen), so
-     * navigational focus should be shown.
-     */
-    public static final int RELAYOUT_RES_IN_TOUCH_MODE = 0x1;
-
-    /**
-     * This is the first time the window is being drawn,
-     * so the client must call drawingFinished() when done
-     */
-    public static final int RELAYOUT_RES_FIRST_TIME = 0x2;
-
-    /**
-     * The window manager has changed the surface from the last call.
-     */
-    public static final int RELAYOUT_RES_SURFACE_CHANGED = 0x4;
-
-    /**
-     * The window manager is currently animating.  It will call
-     * IWindow.doneAnimating() when done.
-     */
-    public static final int RELAYOUT_RES_ANIMATING = 0x8;
-
-    /**
-     * Flag for relayout: the client will be later giving
-     * internal insets; as a result, the window will not impact other window
-     * layouts until the insets are given.
-     */
-    public static final int RELAYOUT_INSETS_PENDING = 0x1;
-
-    /**
-     * Flag for relayout: the client may be currently using the current surface,
-     * so if it is to be destroyed as a part of the relayout the destroy must
-     * be deferred until later.  The client will call performDeferredDestroy()
-     * when it is okay.
-     */
-    public static final int RELAYOUT_DEFER_SURFACE_DESTROY = 0x2;
-
-    public static final int ADD_FLAG_APP_VISIBLE = 0x2;
-    public static final int ADD_FLAG_IN_TOUCH_MODE = RELAYOUT_RES_IN_TOUCH_MODE;
-    
-    public static final int ADD_OKAY = 0;
-    public static final int ADD_BAD_APP_TOKEN = -1;
-    public static final int ADD_BAD_SUBWINDOW_TOKEN = -2;
-    public static final int ADD_NOT_APP_TOKEN = -3;
-    public static final int ADD_APP_EXITING = -4;
-    public static final int ADD_DUPLICATE_ADD = -5;
-    public static final int ADD_STARTING_NOT_NEEDED = -6;
-    public static final int ADD_MULTIPLE_SINGLETON = -7;
-    public static final int ADD_PERMISSION_DENIED = -8;
-
-    private static WindowManagerImpl sDefaultWindowManager;
-    private static IWindowManager sWindowManagerService;
-
-    private final WindowManagerState mState;
+public final class WindowManagerImpl implements WindowManager {
+    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
+    private final Context mContext;
+    private final Display mDisplay;
     private final Window mParentWindow;
-    private final CompatibilityInfoHolder mCompatibilityInfo;
-    private final Display mDefaultDisplay;
 
-    private WindowManagerImpl(WindowManagerState state, Window parentWindow,
-            CompatibilityInfoHolder compatibilityInfo) {
-        mState = state;
+    public WindowManagerImpl(Context context, int displayId) {
+        mContext = context;
+        mDisplay = DisplayManager.getInstance().getDisplay(displayId, mContext);
+        mParentWindow = null;
+    }
+
+    private WindowManagerImpl(Context context, Display display, Window parentWindow) {
+        mContext = context;
+        mDisplay = display;
         mParentWindow = parentWindow;
-        mCompatibilityInfo = compatibilityInfo;
-        mDefaultDisplay = mState.getDefaultDisplay(mCompatibilityInfo);
     }
 
-    public static WindowManagerImpl getDefault() {
-        synchronized (WindowManagerImpl.class) {
-            if (sDefaultWindowManager == null) {
-                sDefaultWindowManager = new WindowManagerImpl(
-                        new WindowManagerState(), null, null);
-            }
-            return sDefaultWindowManager;
-        }
-    }
-
-    public static IWindowManager getWindowManagerService() {
-        synchronized (WindowManagerImpl.class) {
-            if (sWindowManagerService == null) {
-                sWindowManagerService = IWindowManager.Stub.asInterface(
-                        ServiceManager.getService("window"));
-            }
-            return sWindowManagerService;
-        }
-    }
-
-    public WindowManagerImpl makeLocal(Window parentWindow) {
-        return new WindowManagerImpl(mState, parentWindow, parentWindow.getCompatibilityInfo());
-    }
-
-    public WindowManagerImpl makeCompatible(CompatibilityInfoHolder compatInfo) {
-        if (compatInfo == mCompatibilityInfo) {
-            return this;
-        }
-        if (compatInfo == null && mParentWindow == null) {
-            return getDefault();
-        }
-        return new WindowManagerImpl(mState, mParentWindow, compatInfo);
+    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
+        return new WindowManagerImpl(mContext, mDisplay, parentWindow);
     }
 
     @Override
     public void addView(View view, ViewGroup.LayoutParams params) {
-        mState.addView(view, params, mParentWindow, mCompatibilityInfo);
+        mGlobal.addView(view, params, mDisplay, mParentWindow);
     }
 
     @Override
     public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
-        mState.updateViewLayout(view, params);
+        mGlobal.updateViewLayout(view, params);
     }
 
     @Override
     public void removeView(View view) {
-        mState.removeView(view, false);
+        mGlobal.removeView(view, false);
     }
 
     @Override
     public void removeViewImmediate(View view) {
-        mState.removeView(view, true);
+        mGlobal.removeView(view, true);
     }
 
     @Override
     public Display getDefaultDisplay() {
-        return mDefaultDisplay;
-    }
-
-    public void closeAll(IBinder token, String who, String what) {
-        mState.closeAll(token, who, what);
-    }
-
-    public void startTrimMemory(int level) {
-        mState.startTrimMemory(level);
-    }
-
-    public void endTrimMemory() {
-        mState.endTrimMemory();
-    }
-
-    public void trimLocalMemory() {
-        mState.trimLocalMemory();
-    }
-
-    public void dumpGfxInfo(FileDescriptor fd) {
-        mState.dumpGfxInfo(fd);
-    }
-
-    public void setStoppedState(IBinder token, boolean stopped) {
-        mState.setStoppedState(token, stopped);
-    }
-
-    public void reportNewConfiguration(Configuration config) {
-        mState.reportNewConfiguration(config);
-    }
-
-    static final class WindowManagerState {
-        private final Display mDefaultDisplay;
-
-        private View[] mViews;
-        private ViewRootImpl[] mRoots;
-        private WindowManager.LayoutParams[] mParams;
-        private boolean mNeedsEglTerminate;
-
-        private Runnable mSystemPropertyUpdater;
-
-        public WindowManagerState() {
-            mDefaultDisplay = new Display(Display.DEFAULT_DISPLAY, null);
-        }
-
-        public Display getDefaultDisplay(CompatibilityInfoHolder compatInfo) {
-            if (compatInfo == null) {
-                return mDefaultDisplay;
-            }
-            return new Display(Display.DEFAULT_DISPLAY, compatInfo);
-        }
-
-        public void addView(View view, ViewGroup.LayoutParams params, Window parentWindow,
-                CompatibilityInfoHolder cih) {
-            if (!(params instanceof WindowManager.LayoutParams)) {
-                throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
-            }
-
-            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
-            if (parentWindow != null) {
-                parentWindow.adjustLayoutParamsForSubWindow(wparams);
-            }
-
-            ViewRootImpl root;
-            View panelParentView = null;
-
-            synchronized (this) {
-                // Start watching for system property changes.
-                if (mSystemPropertyUpdater == null) {
-                    mSystemPropertyUpdater = new Runnable() {
-                        @Override public void run() {
-                            synchronized (this) {
-                                synchronized (this) {
-                                    for (ViewRootImpl root : mRoots) {
-                                        root.loadSystemProperties();
-                                    }
-                                }
-                            }
-                        }
-                    };
-                    SystemProperties.addChangeCallback(mSystemPropertyUpdater);
-                }
-
-                int index = findViewLocked(view, false);
-                if (index >= 0) {
-                    throw new IllegalStateException("View " + view
-                            + " has already been added to the window manager.");
-                }
-
-                // If this is a panel window, then find the window it is being
-                // attached to for future reference.
-                if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
-                        wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
-                    final int count = mViews != null ? mViews.length : 0;
-                    for (int i=0; i<count; i++) {
-                        if (mRoots[i].mWindow.asBinder() == wparams.token) {
-                            panelParentView = mViews[i];
-                        }
-                    }
-                }
-
-                root = new ViewRootImpl(view.getContext());
-                if (cih == null) {
-                    root.mCompatibilityInfo = new CompatibilityInfoHolder();
-                } else {
-                    root.mCompatibilityInfo = cih;
-                }
-
-                view.setLayoutParams(wparams);
-
-                if (mViews == null) {
-                    index = 1;
-                    mViews = new View[1];
-                    mRoots = new ViewRootImpl[1];
-                    mParams = new WindowManager.LayoutParams[1];
-                } else {
-                    index = mViews.length + 1;
-                    Object[] old = mViews;
-                    mViews = new View[index];
-                    System.arraycopy(old, 0, mViews, 0, index-1);
-                    old = mRoots;
-                    mRoots = new ViewRootImpl[index];
-                    System.arraycopy(old, 0, mRoots, 0, index-1);
-                    old = mParams;
-                    mParams = new WindowManager.LayoutParams[index];
-                    System.arraycopy(old, 0, mParams, 0, index-1);
-                }
-                index--;
-
-                mViews[index] = view;
-                mRoots[index] = root;
-                mParams[index] = wparams;
-            }
-
-            // do this last because it fires off messages to start doing things
-            root.setView(view, wparams, panelParentView);
-        }
-
-        public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
-            if (!(params instanceof WindowManager.LayoutParams)) {
-                throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
-            }
-
-            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
-
-            view.setLayoutParams(wparams);
-
-            synchronized (this) {
-                int index = findViewLocked(view, true);
-                ViewRootImpl root = mRoots[index];
-                mParams[index] = wparams;
-                root.setLayoutParams(wparams, false);
-            }
-        }
-
-        public void removeView(View view, boolean immediate) {
-            synchronized (this) {
-                int index = findViewLocked(view, true);
-                View curView = removeViewLocked(index, immediate);
-                if (curView == view) {
-                    return;
-                }
-
-                throw new IllegalStateException("Calling with view " + view
-                        + " but the ViewAncestor is attached to " + curView);
-            }
-        }
-
-        public void closeAll(IBinder token, String who, String what) {
-            synchronized (this) {
-                if (mViews == null)
-                    return;
-
-                int count = mViews.length;
-                //Log.i("foo", "Closing all windows of " + token);
-                for (int i=0; i<count; i++) {
-                    //Log.i("foo", "@ " + i + " token " + mParams[i].token
-                    //        + " view " + mRoots[i].getView());
-                    if (token == null || mParams[i].token == token) {
-                        ViewRootImpl root = mRoots[i];
-
-                        //Log.i("foo", "Force closing " + root);
-                        if (who != null) {
-                            WindowLeaked leak = new WindowLeaked(
-                                    what + " " + who + " has leaked window "
-                                    + root.getView() + " that was originally added here");
-                            leak.setStackTrace(root.getLocation().getStackTrace());
-                            Log.e(TAG, leak.getMessage(), leak);
-                        }
-
-                        removeViewLocked(i, false);
-                        i--;
-                        count--;
-                    }
-                }
-            }
-        }
-
-        private View removeViewLocked(int index, boolean immediate) {
-            ViewRootImpl root = mRoots[index];
-            View view = root.getView();
-
-            if (view != null) {
-                InputMethodManager imm = InputMethodManager.getInstance(view.getContext());
-                if (imm != null) {
-                    imm.windowDismissed(mViews[index].getWindowToken());
-                }
-            }
-            root.die(immediate);
-
-            final int count = mViews.length;
-
-            // remove it from the list
-            View[] tmpViews = new View[count-1];
-            removeItem(tmpViews, mViews, index);
-            mViews = tmpViews;
-
-            ViewRootImpl[] tmpRoots = new ViewRootImpl[count-1];
-            removeItem(tmpRoots, mRoots, index);
-            mRoots = tmpRoots;
-
-            WindowManager.LayoutParams[] tmpParams
-                    = new WindowManager.LayoutParams[count-1];
-            removeItem(tmpParams, mParams, index);
-            mParams = tmpParams;
-
-            if (view != null) {
-                view.assignParent(null);
-                // func doesn't allow null...  does it matter if we clear them?
-                //view.setLayoutParams(null);
-            }
-            return view;
-        }
-
-        private static void removeItem(Object[] dst, Object[] src, int index) {
-            if (dst.length > 0) {
-                if (index > 0) {
-                    System.arraycopy(src, 0, dst, 0, index);
-                }
-                if (index < dst.length) {
-                    System.arraycopy(src, index+1, dst, index, src.length-index-1);
-                }
-            }
-        }
-
-        private int findViewLocked(View view, boolean required) {
-            synchronized (this) {
-                if (mViews != null) {
-                    final int count = mViews.length;
-                    for (int i = 0; i < count; i++) {
-                        if (mViews[i] == view) {
-                            return i;
-                        }
-                    }
-                }
-                if (required) {
-                    throw new IllegalArgumentException("View not attached to window manager");
-                }
-                return -1;
-            }
-        }
-
-        public void startTrimMemory(int level) {
-            if (HardwareRenderer.isAvailable()) {
-                // On low-end gfx devices we trim when memory is moderate;
-                // on high-end devices we do this when low.
-                if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
-                        || (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE
-                                && !ActivityManager.isHighEndGfx(mDefaultDisplay))) {
-                    // Destroy all hardware surfaces and resources associated to
-                    // known windows
-                    synchronized (this) {
-                        if (mViews == null) return;
-                        int count = mViews.length;
-                        for (int i = 0; i < count; i++) {
-                            mRoots[i].terminateHardwareResources();
-                        }
-                    }
-                    // Force a full memory flush
-                    mNeedsEglTerminate = true;
-                    HardwareRenderer.startTrimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
-                    return;
-                }
-
-                HardwareRenderer.startTrimMemory(level);
-            }
-        }
-
-        public void endTrimMemory() {
-            HardwareRenderer.endTrimMemory();
-
-            if (mNeedsEglTerminate) {
-                ManagedEGLContext.doTerminate();
-                mNeedsEglTerminate = false;
-            }
-        }
-
-        public void trimLocalMemory() {
-            synchronized (this) {
-                if (mViews == null) return;
-                int count = mViews.length;
-                for (int i = 0; i < count; i++) {
-                    mRoots[i].destroyHardwareLayers();
-                }
-            }
-        }
-
-        public void dumpGfxInfo(FileDescriptor fd) {
-            FileOutputStream fout = new FileOutputStream(fd);
-            PrintWriter pw = new PrintWriter(fout);
-            try {
-                synchronized (this) {
-                    if (mViews != null) {
-                        final int count = mViews.length;
-
-                        pw.println("Profile data in ms:");
-
-                        for (int i = 0; i < count; i++) {
-                            ViewRootImpl root = mRoots[i];
-                            String name = getWindowName(root);
-                            pw.printf("\n\t%s", name);
-
-                            HardwareRenderer renderer =
-                                    root.getView().mAttachInfo.mHardwareRenderer;
-                            if (renderer != null) {
-                                renderer.dumpGfxInfo(pw);
-                            }
-                        }
-
-                        pw.println("\nView hierarchy:\n");
-
-                        int viewsCount = 0;
-                        int displayListsSize = 0;
-                        int[] info = new int[2];
-
-                        for (int i = 0; i < count; i++) {
-                            ViewRootImpl root = mRoots[i];
-                            root.dumpGfxInfo(info);
-
-                            String name = getWindowName(root);
-                            pw.printf("  %s\n  %d views, %.2f kB of display lists",
-                                    name, info[0], info[1] / 1024.0f);
-                            HardwareRenderer renderer =
-                                    root.getView().mAttachInfo.mHardwareRenderer;
-                            if (renderer != null) {
-                                pw.printf(", %d frames rendered", renderer.getFrameCount());
-                            }
-                            pw.printf("\n\n");
-
-                            viewsCount += info[0];
-                            displayListsSize += info[1];
-                        }
-
-                        pw.printf("\nTotal ViewRootImpl: %d\n", count);
-                        pw.printf("Total Views:        %d\n", viewsCount);
-                        pw.printf("Total DisplayList:  %.2f kB\n\n", displayListsSize / 1024.0f);
-                    }
-                }
-            } finally {
-                pw.flush();
-            }
-        }
-
-        private static String getWindowName(ViewRootImpl root) {
-            return root.mWindowAttributes.getTitle() + "/" +
-                    root.getClass().getName() + '@' + Integer.toHexString(root.hashCode());
-        }
-
-        public void setStoppedState(IBinder token, boolean stopped) {
-            synchronized (this) {
-                if (mViews != null) {
-                    int count = mViews.length;
-                    for (int i=0; i < count; i++) {
-                        if (token == null || mParams[i].token == token) {
-                            ViewRootImpl root = mRoots[i];
-                            root.setStopped(stopped);
-                        }
-                    }
-                }
-            }
-        }
-
-        public void reportNewConfiguration(Configuration config) {
-            synchronized (this) {
-                if (mViews != null) {
-                    int count = mViews.length;
-                    config = new Configuration(config);
-                    for (int i=0; i < count; i++) {
-                        ViewRootImpl root = mRoots[i];
-                        root.requestUpdateConfiguration(config);
-                    }
-                }
-            }
-        }
+        return mDisplay;
     }
 }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 407bae5..7173d1d 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -22,7 +22,6 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.IBinder;
-import android.os.LocalPowerManager;
 import android.os.Looper;
 import android.view.animation.Animation;
 
@@ -115,11 +114,11 @@
     public final static int ACTION_PASS_TO_USER = 0x00000001;
 
     /**
-     * This key event should extend the user activity timeout and turn the lights on.
+     * This key event should wake the device.
      * To be returned from {@link #interceptKeyBeforeQueueing}.
      * Do not return this and {@link #ACTION_GO_TO_SLEEP} or {@link #ACTION_PASS_TO_USER}.
      */
-    public final static int ACTION_POKE_USER_ACTIVITY = 0x00000002;
+    public final static int ACTION_WAKE_UP = 0x00000002;
 
     /**
      * This key event should put the device to sleep (and engage keyguard if necessary)
@@ -391,8 +390,8 @@
          */
         public void switchKeyboardLayout(int deviceId, int direction);
 
-        public void shutdown();
-        public void rebootSafeMode();
+        public void shutdown(boolean confirm);
+        public void rebootSafeMode(boolean confirm);
     }
 
     /**
@@ -473,11 +472,9 @@
      * Perform initialization of the policy.
      * 
      * @param context The system context we are running in.
-     * @param powerManager 
      */
     public void init(Context context, IWindowManager windowManager,
-            WindowManagerFuncs windowManagerFuncs,
-            LocalPowerManager powerManager);
+            WindowManagerFuncs windowManagerFuncs);
 
     /**
      * Called by window manager once it has the initial, default native
@@ -490,9 +487,9 @@
      * 
      * @param attrs The window's LayoutParams. 
      *  
-     * @return {@link WindowManagerImpl#ADD_OKAY} if the add can proceed;
+     * @return {@link WindowManagerGlobal#ADD_OKAY} if the add can proceed;
      *      else an error code, usually
-     *      {@link WindowManagerImpl#ADD_PERMISSION_DENIED}, to abort the add.
+     *      {@link WindowManagerGlobal#ADD_PERMISSION_DENIED}, to abort the add.
      */
     public int checkAddPermission(WindowManager.LayoutParams attrs);
 
@@ -665,7 +662,7 @@
      * @param win The window being added.
      * @param attrs The window's LayoutParams. 
      *  
-     * @return {@link WindowManagerImpl#ADD_OKAY} if the add can proceed, else an 
+     * @return {@link WindowManagerGlobal#ADD_OKAY} if the add can proceed, else an
      *         error code to abort the add.
      */
     public int prepareAddWindowLw(WindowState win,
@@ -1093,31 +1090,6 @@
     public void lockNow();
 
     /**
-     * Check to see if a screensaver should be run instead of powering off the screen on timeout. 
-     * 
-     * @return true if the screensaver should run, false if the screen should turn off.
-     * 
-     * @hide
-     */
-    public boolean isScreenSaverEnabled();
-
-    /**
-     * Start the screensaver (if it is enabled and not yet running).
-     * 
-     * @return Whether the screensaver was successfully started.
-     * 
-     * @hide
-     */
-    public boolean startScreenSaver();
-
-    /**
-     * Stop the screensaver if it is running.
-     * 
-     * @hide
-     */
-    public void stopScreenSaver();
-
-    /**
      * Set the last used input method window state. This state is used to make IME transition
      * smooth.
      * @hide
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 30c713e..2b75d83 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -37,8 +37,8 @@
     /**
      * Gets the singleton CookieManager instance. If this method is used
      * before the application instantiates a {@link WebView} instance,
-     * {@link CookieSyncManager#createInstance(Context)} must be called
-     * first.
+     * {@link CookieSyncManager#createInstance CookieSyncManager.createInstance(Context)}
+     * must be called first.
      *
      * @return the singleton CookieManager instance
      */
diff --git a/core/java/android/webkit/DeviceOrientationService.java b/core/java/android/webkit/DeviceOrientationService.java
index 2e8656c..a4d240d 100755
--- a/core/java/android/webkit/DeviceOrientationService.java
+++ b/core/java/android/webkit/DeviceOrientationService.java
@@ -123,7 +123,7 @@
         // The angles are in radians
         float[] rotationAngles = new float[3];
         SensorManager.getOrientation(deviceRotationMatrix, rotationAngles);
-        double alpha = Math.toDegrees(-rotationAngles[0]) - 90.0;
+        double alpha = Math.toDegrees(-rotationAngles[0]);
         while (alpha < 0.0) { alpha += 360.0; } // [0, 360)
         double beta = Math.toDegrees(-rotationAngles[1]);
         while (beta < -180.0) { beta += 360.0; } // [-180, 180)
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 193e98d..e8ff01f 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -16,8 +16,7 @@
 
 package android.webkit;
 
-import android.os.Message;
-import android.os.Build;
+import android.content.Context;
 
 /**
  * Manages settings state for a WebView. When a WebView is first created, it
@@ -422,7 +421,7 @@
      * Gets the text zoom of the page in percent.
      *
      * @return the text zoom of the page in percent
-     * @see #setTextSizeZoom
+     * @see #setTextZoom
      */
     public synchronized int getTextZoom() {
         throw new MustOverrideException();
@@ -435,7 +434,7 @@
      * @deprecated Use {@link #setTextZoom} instead.
      */
     public synchronized void setTextSize(TextSize t) {
-        throw new MustOverrideException();
+        setTextZoom(t.value);
     }
 
     /**
@@ -448,7 +447,20 @@
      * @deprecated Use {@link #getTextZoom} instead.
      */
     public synchronized TextSize getTextSize() {
-        throw new MustOverrideException();
+        TextSize closestSize = null;
+        int smallestDelta = Integer.MAX_VALUE;
+        int textSize = getTextZoom();
+        for (TextSize size : TextSize.values()) {
+            int delta = Math.abs(textSize - size.value);
+            if (delta == 0) {
+                return size;
+            }
+            if (delta < smallestDelta) {
+                smallestDelta = delta;
+                closestSize = size;
+            }
+        }
+        return closestSize != null ? closestSize : TextSize.NORMAL;
     }
 
     /**
@@ -1226,6 +1238,18 @@
     }
 
     /**
+     * Returns the default User-Agent used by a WebView.
+     * An instance of WebView could use a different User-Agent if a call
+     * is made to {@link WebSettings#setUserAgent(int)} or
+     * {@link WebSettings#setUserAgentString(String)}.
+     *
+     * @param context a Context object used to access application assets
+     */
+    public static String getDefaultUserAgent(Context context) {
+        return WebViewFactory.getProvider().getStatics().getDefaultUserAgent(context);
+    }
+
+    /**
      * Tells the WebView whether it needs to set a node to have focus when
      * {@link WebView#requestFocus(int, android.graphics.Rect)} is called. The
      * default value is true.
diff --git a/core/java/android/webkit/WebSettingsClassic.java b/core/java/android/webkit/WebSettingsClassic.java
index 66651f7..d1f8b4b 100644
--- a/core/java/android/webkit/WebSettingsClassic.java
+++ b/core/java/android/webkit/WebSettingsClassic.java
@@ -374,6 +374,21 @@
         synchronized(sLockForLocaleSettings) {
             locale = sLocale;
         }
+        return getDefaultUserAgentForLocale(mContext, locale);
+    }
+
+    /**
+     * Returns the default User-Agent used by a WebView.
+     * An instance of WebView could use a different User-Agent if a call
+     * is made to {@link WebSettings#setUserAgent(int)} or
+     * {@link WebSettings#setUserAgentString(String)}.
+     *
+     * @param context a Context object used to access application assets
+     * @param locale The Locale to use in the User-Agent string.
+     * @see WebViewFactoryProvider#getDefaultUserAgent(Context)
+     * @see WebView#getDefaultUserAgent(Context)
+     */
+    public static String getDefaultUserAgentForLocale(Context context, Locale locale) {
         StringBuffer buffer = new StringBuffer();
         // Add version
         final String version = Build.VERSION.RELEASE;
@@ -417,9 +432,9 @@
             buffer.append(" Build/");
             buffer.append(id);
         }
-        String mobile = mContext.getResources().getText(
+        String mobile = context.getResources().getText(
             com.android.internal.R.string.web_user_agent_target_content).toString();
-        final String base = mContext.getResources().getText(
+        final String base = context.getResources().getText(
                 com.android.internal.R.string.web_user_agent).toString();
         return String.format(base, buffer, mobile);
     }
@@ -650,34 +665,6 @@
     }
 
     /**
-     * @see android.webkit.WebSettings#setTextSize(android.webkit.WebSettingsClassic.TextSize)
-     */
-    @Override
-    public synchronized void setTextSize(TextSize t) {
-        setTextZoom(t.value);
-    }
-
-    /**
-     * @see android.webkit.WebSettings#getTextSize()
-     */
-    @Override
-    public synchronized TextSize getTextSize() {
-        TextSize closestSize = null;
-        int smallestDelta = Integer.MAX_VALUE;
-        for (TextSize size : TextSize.values()) {
-            int delta = Math.abs(mTextSize - size.value);
-            if (delta == 0) {
-                return size;
-            }
-            if (delta < smallestDelta) {
-                smallestDelta = delta;
-                closestSize = size;
-            }
-        }
-        return closestSize != null ? closestSize : TextSize.NORMAL;
-    }
-
-    /**
      * Set the double-tap zoom of the page in percent. Default is 100.
      * @param doubleTapZoom A percent value for increasing or decreasing the double-tap zoom.
      */
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6e4e82c..82635d7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -164,10 +164,7 @@
  *
  * <p>For obvious security reasons, your application has its own
  * cache, cookie store etc.&mdash;it does not share the Browser
- * application's data. Cookies are managed on a separate thread, so
- * operations like index building don't block the UI
- * thread. Follow the instructions in {@link android.webkit.CookieSyncManager}
- * if you want to use cookies in your application.
+ * application's data.
  * </p>
  *
  * <p>By default, requests by the HTML to open new windows are
@@ -313,15 +310,15 @@
         /**
          * Notifies the listener about progress made by a find operation.
          *
-         * @param numberOfMatches how many matches have been found
          * @param activeMatchOrdinal the zero-based ordinal of the currently selected match
+         * @param numberOfMatches how many matches have been found
          * @param isDoneCounting whether the find operation has actually completed. The listener
          *                       may be notified multiple times while the
          *                       operation is underway, and the numberOfMatches
          *                       value should not be considered final unless
          *                       isDoneCounting is true.
          */
-        public void onFindResultReceived(int numberOfMatches, int activeMatchOrdinal,
+        public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
             boolean isDoneCounting);
     }
 
@@ -801,11 +798,13 @@
      * #loadDataWithBaseURL(String,String,String,String,String)
      * loadDataWithBaseURL()} with an appropriate base URL.
      * <p>
-     * If the value of the encoding parameter is 'base64', then the data must
-     * be encoded as base64. Otherwise, the data must use ASCII encoding for
+     * The encoding parameter specifies whether the data is base64 or URL
+     * encoded. If the data is base64 encoded, the value of the encoding
+     * parameter must be 'base64'. For all other values of the parameter,
+     * including null, it is assumed that the data uses ASCII encoding for
      * octets inside the range of safe URL characters and use the standard %xx
-     * hex encoding of URLs for octets outside that range. For example,
-     * '#', '%', '\', '?' should be replaced by %23, %25, %27, %3f respectively.
+     * hex encoding of URLs for octets outside that range. For example, '#',
+     * '%', '\', '?' should be replaced by %23, %25, %27, %3f respectively.
      * <p>
      * The 'data' scheme URL formed by this method uses the default US-ASCII
      * charset. If you need need to set a different charset, you should form a
@@ -1404,7 +1403,6 @@
      * @return the address, or if no address is found, null
      */
     public static String findAddress(String addr) {
-        checkThread();
         return getFactory().getStatics().findAddress(addr);
     }
 
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 5b8764b..9df4852 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.accessibilityservice.AccessibilityServiceInfo;
 import android.animation.ObjectAnimator;
 import android.annotation.Widget;
 import android.app.ActivityManager;
@@ -131,6 +132,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.Vector;
@@ -378,28 +380,26 @@
                     imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS;
                 }
             }
+            int action = EditorInfo.IME_ACTION_GO;
             switch (type) {
                 case WebTextView.NORMAL_TEXT_FIELD:
-                    imeOptions |= EditorInfo.IME_ACTION_GO;
                     break;
                 case WebTextView.TEXT_AREA:
                     inputType |= InputType.TYPE_TEXT_FLAG_MULTI_LINE
                             | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
                             | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;
-                    imeOptions |= EditorInfo.IME_ACTION_NONE;
+                    action = EditorInfo.IME_ACTION_NONE;
                     break;
                 case WebTextView.PASSWORD:
                     inputType |= EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD;
-                    imeOptions |= EditorInfo.IME_ACTION_GO;
                     break;
                 case WebTextView.SEARCH:
-                    imeOptions |= EditorInfo.IME_ACTION_SEARCH;
+                    action = EditorInfo.IME_ACTION_SEARCH;
                     break;
                 case WebTextView.EMAIL:
                     // inputType needs to be overwritten because of the different text variation.
                     inputType = InputType.TYPE_CLASS_TEXT
                             | InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
-                    imeOptions |= EditorInfo.IME_ACTION_GO;
                     break;
                 case WebTextView.NUMBER:
                     // inputType needs to be overwritten because of the different class.
@@ -407,23 +407,20 @@
                             | InputType.TYPE_NUMBER_FLAG_SIGNED | InputType.TYPE_NUMBER_FLAG_DECIMAL;
                     // Number and telephone do not have both a Tab key and an
                     // action, so set the action to NEXT
-                    imeOptions |= EditorInfo.IME_ACTION_NEXT;
                     break;
                 case WebTextView.TELEPHONE:
                     // inputType needs to be overwritten because of the different class.
                     inputType = InputType.TYPE_CLASS_PHONE;
-                    imeOptions |= EditorInfo.IME_ACTION_NEXT;
                     break;
                 case WebTextView.URL:
                     // TYPE_TEXT_VARIATION_URI prevents Tab key from showing, so
                     // exclude it for now.
-                    imeOptions |= EditorInfo.IME_ACTION_GO;
                     inputType |= InputType.TYPE_TEXT_VARIATION_URI;
                     break;
                 default:
-                    imeOptions |= EditorInfo.IME_ACTION_GO;
                     break;
             }
+            imeOptions |= action;
             mHint = initData.mLabel;
             mInputType = inputType;
             mImeOptions = imeOptions;
@@ -1312,6 +1309,12 @@
         public WebViewDatabase getWebViewDatabase(Context context) {
             return WebViewDatabaseClassic.getInstance(context);
         }
+
+        @Override
+        public String getDefaultUserAgent(Context context) {
+            return WebSettingsClassic.getDefaultUserAgentForLocale(context,
+                    Locale.getDefault());
+        }
     }
 
     private void onHandleUiEvent(MotionEvent event, int eventType, int flags) {
@@ -1743,8 +1746,21 @@
         event.setMaxScrollY(Math.max(convertedContentHeight - adjustedViewHeight, 0));
     }
 
-    private boolean isAccessibilityEnabled() {
-        return AccessibilityManager.getInstance(mContext).isEnabled();
+    private boolean isAccessibilityInjectionEnabled() {
+        final AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
+        if (!manager.isEnabled()) {
+            return false;
+        }
+
+        // Accessibility scripts should be injected only when a speaking service
+        // is enabled. This may need to change later to accommodate Braille.
+        final List<AccessibilityServiceInfo> services = manager.getEnabledAccessibilityServiceList(
+                AccessibilityServiceInfo.FEEDBACK_SPOKEN);
+        if (services.isEmpty()) {
+            return false;
+        }
+
+        return true;
     }
 
     private AccessibilityInjector getAccessibilityInjector() {
@@ -3930,7 +3946,7 @@
 
         // reset the flag since we set to true in if need after
         // loading is see onPageFinished(Url)
-        if (isAccessibilityEnabled()) {
+        if (isAccessibilityInjectionEnabled()) {
             getAccessibilityInjector().onPageStarted(url);
         }
 
@@ -3945,7 +3961,7 @@
     /* package */ void onPageFinished(String url) {
         mZoomManager.onPageFinished(url);
 
-        if (isAccessibilityEnabled()) {
+        if (isAccessibilityInjectionEnabled()) {
             getAccessibilityInjector().onPageFinished(url);
         }
     }
@@ -4986,7 +5002,7 @@
         }
 
         // See if the accessibility injector needs to handle this event.
-        if (isAccessibilityEnabled()
+        if (isAccessibilityInjectionEnabled()
                 && getAccessibilityInjector().handleKeyEventIfNecessary(event)) {
             return true;
         }
@@ -5093,7 +5109,7 @@
         }
 
         // See if the accessibility injector needs to handle this event.
-        if (isAccessibilityEnabled()
+        if (isAccessibilityInjectionEnabled()
                 && getAccessibilityInjector().handleKeyEventIfNecessary(event)) {
             return true;
         }
@@ -5344,7 +5360,7 @@
     public void onAttachedToWindow() {
         if (mWebView.hasWindowFocus()) setActive(true);
 
-        if (isAccessibilityEnabled()) {
+        if (isAccessibilityInjectionEnabled()) {
             getAccessibilityInjector().addAccessibilityApisIfNecessary();
         }
 
@@ -5357,7 +5373,7 @@
         mZoomManager.dismissZoomPicker();
         if (mWebView.hasWindowFocus()) setActive(false);
 
-        if (isAccessibilityEnabled()) {
+        if (isAccessibilityInjectionEnabled()) {
             getAccessibilityInjector().removeAccessibilityApisIfNecessary();
         } else {
             // Ensure the injector is cleared if we're detaching from the window
@@ -6432,9 +6448,13 @@
                                 mWebViewPrivate.getVerticalScrollFactor());
                         final int hdelta = (int) (hscroll *
                                 mWebViewPrivate.getHorizontalScrollFactor());
-                        if (pinScrollBy(hdelta, vdelta, false, 0)) {
-                            return true;
-                        }
+
+                        abortAnimation();
+                        int oldTouchMode = mTouchMode;
+                        startScrollingLayer(event.getX(), event.getY());
+                        doDrag(hdelta, vdelta);
+                        mTouchMode = oldTouchMode;
+                        return true;
                     }
                 }
             }
@@ -7270,11 +7290,7 @@
                     // nativeCreate sets mNativeClass to a non-zero value
                     String drawableDir = BrowserFrame.getRawResFilename(
                             BrowserFrame.DRAWABLEDIR, mContext);
-                    WindowManager windowManager =
-                            (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
-                    Display display = windowManager.getDefaultDisplay();
-                    nativeCreate(msg.arg1, drawableDir,
-                            ActivityManager.isHighEndGfx(display));
+                    nativeCreate(msg.arg1, drawableDir, ActivityManager.isHighEndGfx());
                     if (mDelaySetPicture != null) {
                         setNewPicture(mDelaySetPicture, true);
                         mDelaySetPicture = null;
@@ -7439,7 +7455,7 @@
                     break;
 
                 case SELECTION_STRING_CHANGED:
-                    if (isAccessibilityEnabled()) {
+                    if (isAccessibilityInjectionEnabled()) {
                         getAccessibilityInjector()
                                 .handleSelectionChangedIfNecessary((String) msg.obj);
                     }
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 1d302f1..934ef83 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -42,6 +42,12 @@
          * {@link android.webkit.WebView#disablePlatformNotifications()}
          */
         void setPlatformNotificationsEnabled(boolean enable);
+
+        /**
+         * Implements the API method:
+         * {@link android.webkit.WebSettings#getDefaultUserAgent(Context) }
+         */
+        String getDefaultUserAgent(Context context);
     }
 
     Statics getStatics();
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 46079f9..f91201a 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -151,7 +151,7 @@
             mCheckMarkWidth = 0;
         }
         mCheckMarkDrawable = d;
-        // Do padding resolution. This will call setPadding() and do a requestLayout() if needed.
+        // Do padding resolution. This will call internalSetPadding() and do a requestLayout() if needed.
         resolvePadding();
     }
 
@@ -169,6 +169,19 @@
         return mCheckMarkDrawable;
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    protected void internalSetPadding(int left, int top, int right, int bottom) {
+        super.internalSetPadding(left, top, right, bottom);
+        if (isLayoutRtl()) {
+            mBasePadding = mUserPaddingLeft;
+        } else {
+            mBasePadding = mUserPaddingRight;
+        }
+    }
+
     @Override
     public void onPaddingChanged(int layoutDirection) {
         int newPadding = (mCheckMarkDrawable != null) ?
@@ -221,8 +234,15 @@
             final int width = getWidth();
             final int top = y;
             final int bottom = top + height;
-            final int left = isLayoutRtl ? getPaddingEnd() : width - getPaddingEnd();
-            final int right = left + mCheckMarkWidth;
+            final int left;
+            final int right;
+            if (isLayoutRtl) {
+                right = getPaddingEnd();
+                left = right - mCheckMarkWidth;
+            } else {
+                left = width - getPaddingEnd();
+                right = left + mCheckMarkWidth;
+            }
             checkMarkDrawable.setBounds( left, top, right, bottom);
             checkMarkDrawable.draw(canvas);
         }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index dd05a03..dcf90e9 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -61,9 +61,9 @@
  * the content of the inflated hierarchy.
  */
 public class RemoteViews implements Parcelable, Filter {
-    
+
     private static final String LOG_TAG = "RemoteViews";
-    
+
     /**
      * The intent extra that contains the appWidgetId.
      * @hide
@@ -71,11 +71,11 @@
     static final String EXTRA_REMOTEADAPTER_APPWIDGET_ID = "remoteAdapterAppWidgetId";
 
     /**
-     * The package name of the package containing the layout 
+     * The package name of the package containing the layout
      * resource. (Added to the parcel)
      */
     private final String mPackage;
-    
+
     /**
      * The resource ID of the layout file. (Added to the parcel)
      */
@@ -86,7 +86,7 @@
      * inflated
      */
     private ArrayList<Action> mActions;
-    
+
     /**
      * A class to keep track of memory usage by this RemoteViews
      */
@@ -522,13 +522,13 @@
                                     .getCompatibilityInfo().applicationScale;
                             final int[] pos = new int[2];
                             v.getLocationOnScreen(pos);
-    
+
                             final Rect rect = new Rect();
                             rect.left = (int) (pos[0] * appScale + 0.5f);
                             rect.top = (int) (pos[1] * appScale + 0.5f);
                             rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
                             rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
-    
+
                             final Intent intent = new Intent();
                             intent.setSourceBounds(rect);
                             handler.onClickHandler(v, pendingIntent, intent);
@@ -567,7 +567,7 @@
             this.filterMode = mode;
             this.level = level;
         }
-        
+
         public SetDrawableParameters(Parcel parcel) {
             viewId = parcel.readInt();
             targetBackground = parcel.readInt() != 0;
@@ -581,7 +581,7 @@
             }
             level = parcel.readInt();
         }
-        
+
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(TAG);
             dest.writeInt(viewId);
@@ -596,12 +596,12 @@
             }
             dest.writeInt(level);
         }
-        
+
         @Override
         public void apply(View root, ViewGroup rootParent, OnClickHandler handler) {
             final View target = root.findViewById(viewId);
             if (target == null) return;
-            
+
             // Pick the correct drawable to modify for this view
             Drawable targetDrawable = null;
             if (targetBackground) {
@@ -610,7 +610,7 @@
                 ImageView imageView = (ImageView) target;
                 targetDrawable = imageView.getDrawable();
             }
-            
+
             if (targetDrawable != null) {
                 // Perform modifications only if values are set correctly
                 if (alpha != -1) {
@@ -634,7 +634,7 @@
 
         public final static int TAG = 3;
     }
-    
+
     private class ReflectionActionWithoutParams extends Action {
         int viewId;
         String methodName;
@@ -938,7 +938,7 @@
                     out.writeString((String)this.value);
                     break;
                 case CHAR_SEQUENCE:
-                    TextUtils.writeToParcel((CharSequence)this.value, out, flags);   
+                    TextUtils.writeToParcel((CharSequence)this.value, out, flags);
                     break;
                 case URI:
                     out.writeInt(this.value != null ? 1 : 0);
@@ -1314,7 +1314,7 @@
     /**
      * Create a new RemoteViews object that will display the views contained
      * in the specified layout file.
-     * 
+     *
      * @param packageName Name of the package that contains the layout resource
      * @param layoutId The id of the layout resource
      */
@@ -1364,7 +1364,7 @@
 
     /**
      * Reads a RemoteViews object from a parcel.
-     * 
+     *
      * @param parcel
      */
     public RemoteViews(Parcel parcel) {
@@ -1547,7 +1547,7 @@
 
     /**
      * Add an action to be executed on the remote side when apply is called.
-     * 
+     *
      * @param a The action to add
      */
     private void addAction(Action a) {
@@ -1619,7 +1619,7 @@
 
     /**
      * Equivalent to calling View.setVisibility
-     * 
+     *
      * @param viewId The id of the view whose visibility should change
      * @param visibility The new visibility for the view
      */
@@ -1629,7 +1629,7 @@
 
     /**
      * Equivalent to calling TextView.setText
-     * 
+     *
      * @param viewId The id of the view whose text should change
      * @param text The new text for the view
      */
@@ -1639,7 +1639,7 @@
 
     /**
      * Equivalent to calling {@link TextView#setTextSize(int, float)}
-     * 
+     *
      * @param viewId The id of the view whose text size should change
      * @param units The units of size (e.g. COMPLEX_UNIT_SP)
      * @param size The size of the text
@@ -1649,33 +1649,29 @@
     }
 
     /**
-     * Equivalent to calling 
+     * Equivalent to calling
      * {@link TextView#setCompoundDrawablesWithIntrinsicBounds(int, int, int, int)}.
      *
      * @param viewId The id of the view whose text should change
      * @param left The id of a drawable to place to the left of the text, or 0
      * @param top The id of a drawable to place above the text, or 0
      * @param right The id of a drawable to place to the right of the text, or 0
-     * @param bottom The id of a drawable to place below the text, or 0 
+     * @param bottom The id of a drawable to place below the text, or 0
      */
     public void setTextViewCompoundDrawables(int viewId, int left, int top, int right, int bottom) {
         addAction(new TextViewDrawableAction(viewId, false, left, top, right, bottom));
     }
 
     /**
-     * Equivalent to calling {@link 
+     * Equivalent to calling {@link
      * TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(int, int, int, int)}.
      *
      * @param viewId The id of the view whose text should change
-     * @param start The id of a drawable to place before the text (relative to the 
+     * @param start The id of a drawable to place before the text (relative to the
      * layout direction), or 0
      * @param top The id of a drawable to place above the text, or 0
      * @param end The id of a drawable to place after the text, or 0
-<<<<<<< HEAD
-     * @param bottom The id of a drawable to place below the text, or 0 
-=======
      * @param bottom The id of a drawable to place below the text, or 0
->>>>>>> 0a43f67e
      */
     public void setTextViewCompoundDrawablesRelative(int viewId, int start, int top, int end, int bottom) {
         addAction(new TextViewDrawableAction(viewId, true, start, top, end, bottom));
@@ -1683,17 +1679,17 @@
 
     /**
      * Equivalent to calling ImageView.setImageResource
-     * 
+     *
      * @param viewId The id of the view whose drawable should change
      * @param srcId The new resource id for the drawable
      */
-    public void setImageViewResource(int viewId, int srcId) {   
+    public void setImageViewResource(int viewId, int srcId) {
         setInt(viewId, "setImageResource", srcId);
     }
 
     /**
      * Equivalent to calling ImageView.setImageURI
-     * 
+     *
      * @param viewId The id of the view whose drawable should change
      * @param uri The Uri for the image
      */
@@ -1703,7 +1699,7 @@
 
     /**
      * Equivalent to calling ImageView.setImageBitmap
-     * 
+     *
      * @param viewId The id of the view whose bitmap should change
      * @param bitmap The new Bitmap for the drawable
      */
@@ -1726,7 +1722,7 @@
      * {@link Chronometer#setFormat Chronometer.setFormat},
      * and {@link Chronometer#start Chronometer.start()} or
      * {@link Chronometer#stop Chronometer.stop()}.
-     * 
+     *
      * @param viewId The id of the {@link Chronometer} to change
      * @param base The time at which the timer would have read 0:00.  This
      *             time should be based off of
@@ -1740,21 +1736,21 @@
         setString(viewId, "setFormat", format);
         setBoolean(viewId, "setStarted", started);
     }
-    
+
     /**
      * Equivalent to calling {@link ProgressBar#setMax ProgressBar.setMax},
      * {@link ProgressBar#setProgress ProgressBar.setProgress}, and
      * {@link ProgressBar#setIndeterminate ProgressBar.setIndeterminate}
      *
      * If indeterminate is true, then the values for max and progress are ignored.
-     * 
+     *
      * @param viewId The id of the {@link ProgressBar} to change
      * @param max The 100% value for the progress bar
      * @param progress The current value of the progress bar.
-     * @param indeterminate True if the progress bar is indeterminate, 
+     * @param indeterminate True if the progress bar is indeterminate,
      *                false if not.
      */
-    public void setProgressBar(int viewId, int max, int progress, 
+    public void setProgressBar(int viewId, int max, int progress,
             boolean indeterminate) {
         setBoolean(viewId, "setIndeterminate", indeterminate);
         if (!indeterminate) {
@@ -1762,12 +1758,12 @@
             setInt(viewId, "setProgress", progress);
         }
     }
-    
+
     /**
      * Equivalent to calling
      * {@link android.view.View#setOnClickListener(android.view.View.OnClickListener)}
      * to launch the provided {@link PendingIntent}.
-     * 
+     *
      * When setting the on-click action of items within collections (eg. {@link ListView},
      * {@link StackView} etc.), this method will not work. Instead, use {@link
      * RemoteViews#setPendingIntentTemplate(int, PendingIntent) in conjunction with
@@ -1827,7 +1823,7 @@
      * view.
      * <p>
      * You can omit specific calls by marking their values with null or -1.
-     * 
+     *
      * @param viewId The id of the view that contains the target
      *            {@link Drawable}
      * @param targetBackground If true, apply these parameters to the
@@ -1853,7 +1849,7 @@
 
     /**
      * Equivalent to calling {@link android.widget.TextView#setTextColor(int)}.
-     * 
+     *
      * @param viewId The id of the view whose text color should change
      * @param color Sets the text color for all the states (normal, selected,
      *            focused) to be this color.
@@ -2105,16 +2101,16 @@
     /**
      * Inflates the view hierarchy represented by this object and applies
      * all of the actions.
-     * 
+     *
      * <p><strong>Caller beware: this may throw</strong>
-     * 
+     *
      * @param context Default context to use
      * @param parent Parent that the resulting view hierarchy will be attached to. This method
      * does <strong>not</strong> attach the hierarchy. The caller should do so when appropriate.
      * @return The inflated view hierarchy
      */
     public View apply(Context context, ViewGroup parent) {
-        return apply(context, parent, DEFAULT_ON_CLICK_HANDLER);
+        return apply(context, parent, null);
     }
 
     /** @hide */
@@ -2142,12 +2138,12 @@
      * Applies all of the actions to the provided view.
      *
      * <p><strong>Caller beware: this may throw</strong>
-     * 
+     *
      * @param v The view to apply the actions to.  This should be the result of
      * the {@link #apply(Context,ViewGroup)} call.
      */
     public void reapply(Context context, View v) {
-        reapply(context, v, DEFAULT_ON_CLICK_HANDLER);
+        reapply(context, v, null);
     }
 
     /** @hide */
@@ -2170,6 +2166,7 @@
 
     private void performApply(View v, ViewGroup parent, OnClickHandler handler) {
         if (mActions != null) {
+            handler = handler == null ? DEFAULT_ON_CLICK_HANDLER : handler;
             final int count = mActions.size();
             for (int i = 0; i < count; i++) {
                 Action a = mActions.get(i);
@@ -2198,7 +2195,7 @@
 
     /* (non-Javadoc)
      * Used to restrict the views which can be inflated
-     * 
+     *
      * @see android.view.LayoutInflater.Filter#onLoadClass(java.lang.Class)
      */
     public boolean onLoadClass(Class clazz) {
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 5d6491d..1f713d4 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -664,7 +664,7 @@
     @Override
     public void setChecked(boolean checked) {
         super.setChecked(checked);
-        setThumbPosition(checked);
+        setThumbPosition(isChecked());
         invalidate();
     }
 
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 8bb9348..238dc55 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -48,6 +48,10 @@
  */
 public class TabHost extends FrameLayout implements ViewTreeObserver.OnTouchModeChangeListener {
 
+    private static final int TABWIDGET_LOCATION_LEFT = 0;
+    private static final int TABWIDGET_LOCATION_TOP = 1;
+    private static final int TABWIDGET_LOCATION_RIGHT = 2;
+    private static final int TABWIDGET_LOCATION_BOTTOM = 3;
     private TabWidget mTabWidget;
     private FrameLayout mTabContent;
     private List<TabSpec> mTabSpecs = new ArrayList<TabSpec>(2);
@@ -293,22 +297,73 @@
         return mTabContent;
     }
 
+    /**
+     * Get the location of the TabWidget.
+     *
+     * @return The TabWidget location.
+     */
+    private int getTabWidgetLocation() {
+        int location = TABWIDGET_LOCATION_TOP;
+
+        switch (mTabWidget.getOrientation()) {
+            case LinearLayout.VERTICAL:
+                location = (mTabContent.getLeft() < mTabWidget.getLeft()) ? TABWIDGET_LOCATION_RIGHT
+                        : TABWIDGET_LOCATION_LEFT;
+                break;
+            case LinearLayout.HORIZONTAL:
+            default:
+                location = (mTabContent.getTop() < mTabWidget.getTop()) ? TABWIDGET_LOCATION_BOTTOM
+                        : TABWIDGET_LOCATION_TOP;
+                break;
+        }
+        return location;
+    }
+
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         final boolean handled = super.dispatchKeyEvent(event);
 
-        // unhandled key ups change focus to tab indicator for embedded activities
-        // when there is nothing that will take focus from default focus searching
+        // unhandled key events change focus to tab indicator for embedded
+        // activities when there is nothing that will take focus from default
+        // focus searching
         if (!handled
                 && (event.getAction() == KeyEvent.ACTION_DOWN)
-                && (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP)
                 && (mCurrentView != null)
                 && (mCurrentView.isRootNamespace())
-                && (mCurrentView.hasFocus())
-                && (mCurrentView.findFocus().focusSearch(View.FOCUS_UP) == null)) {
-            mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus();
-            playSoundEffect(SoundEffectConstants.NAVIGATION_UP);
-            return true;
+                && (mCurrentView.hasFocus())) {
+            int keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_UP;
+            int directionShouldChangeFocus = View.FOCUS_UP;
+            int soundEffect = SoundEffectConstants.NAVIGATION_UP;
+
+            switch (getTabWidgetLocation()) {
+                case TABWIDGET_LOCATION_LEFT:
+                    keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_LEFT;
+                    directionShouldChangeFocus = View.FOCUS_LEFT;
+                    soundEffect = SoundEffectConstants.NAVIGATION_LEFT;
+                    break;
+                case TABWIDGET_LOCATION_RIGHT:
+                    keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_RIGHT;
+                    directionShouldChangeFocus = View.FOCUS_RIGHT;
+                    soundEffect = SoundEffectConstants.NAVIGATION_RIGHT;
+                    break;
+                case TABWIDGET_LOCATION_BOTTOM:
+                    keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_DOWN;
+                    directionShouldChangeFocus = View.FOCUS_DOWN;
+                    soundEffect = SoundEffectConstants.NAVIGATION_DOWN;
+                    break;
+                case TABWIDGET_LOCATION_TOP:
+                default:
+                    keyCodeShouldChangeFocus = KeyEvent.KEYCODE_DPAD_UP;
+                    directionShouldChangeFocus = View.FOCUS_UP;
+                    soundEffect = SoundEffectConstants.NAVIGATION_UP;
+                    break;
+            }
+            if (event.getKeyCode() == keyCodeShouldChangeFocus
+                    && mCurrentView.findFocus().focusSearch(directionShouldChangeFocus) == null) {
+                mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus();
+                playSoundEffect(soundEffect);
+                return true;
+            }
         }
         return handled;
     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5be9899..f502de4 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2203,6 +2203,27 @@
     }
 
     /**
+     * Get the default {@link Locale} of the text in this TextView.
+     * @return the default {@link Locale} of the text in this TextView.
+     */
+    public Locale getTextLocale() {
+        return mTextPaint.getTextLocale();
+    }
+
+    /**
+     * Set the default {@link Locale} of the text in this TextView to the given value. This value
+     * is used to choose appropriate typefaces for ambiguous characters. Typically used for CJK
+     * locales to disambiguate Hanzi/Kanji/Hanja characters.
+     *
+     * @param locale the {@link Locale} for drawing text, must not be null.
+     *
+     * @see Paint#setTextLocale
+     */
+    public void setTextLocale(Locale locale) {
+        mTextPaint.setTextLocale(locale);
+    }
+
+    /**
      * @return the size (in pixels) of the default text size in this TextView.
      */
     @ViewDebug.ExportedProperty(category = "text")
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 7dcbc3e..053ade7 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -30,7 +30,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.WindowManagerImpl;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 
@@ -331,7 +330,7 @@
         View mView;
         View mNextView;
         
-        WindowManagerImpl mWM;
+        WindowManager mWM;
 
         TN() {
             // XXX This should be changed to use a Dialog, with a Theme.Toast
@@ -371,7 +370,7 @@
                 // remove the old view if necessary
                 handleHide();
                 mView = mNextView;
-                mWM = WindowManagerImpl.getDefault();
+                mWM = (WindowManager)mView.getContext().getSystemService(Context.WINDOW_SERVICE);
                 // We can resolve the Gravity here by using the Locale for getting
                 // the layout direction
                 final Configuration config = mView.getContext().getResources().getConfiguration();
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 84fe8ce..bffbe11 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -37,7 +37,7 @@
 import android.os.PatternMatcher;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -133,7 +133,7 @@
         mAdapter = new ResolveListAdapter(this, intent, initialIntents, rList,
                 mLaunchedFromUid);
         int count = mAdapter.getCount();
-        if (mLaunchedFromUid < 0 || UserId.isIsolated(mLaunchedFromUid)) {
+        if (mLaunchedFromUid < 0 || UserHandle.isIsolated(mLaunchedFromUid)) {
             // Gulp!
             finish();
             return;
@@ -150,7 +150,8 @@
 
             resizeGrid();
         } else if (count == 1) {
-            startActivity(mAdapter.intentForPosition(0));
+            startActivityAsUser(mAdapter.intentForPosition(0),
+                    new UserHandle(UserHandle.getUserId(mLaunchedFromUid)));
             mPackageMonitor.unregister();
             mRegistered = false;
             finish();
@@ -363,12 +364,12 @@
                     if (r.match > bestMatch) bestMatch = r.match;
                 }
                 getPackageManager().addPreferredActivity(filter, bestMatch, set,
-                        intent.getComponent());
+                        intent.getComponent(), UserHandle.getUserId(mLaunchedFromUid));
             }
         }
 
         if (intent != null) {
-            startActivity(intent);
+            startActivityAsUser(intent, new UserHandle(UserHandle.getUserId(mLaunchedFromUid)));
         }
     }
 
@@ -376,7 +377,7 @@
         Intent in = new Intent().setAction("android.settings.APPLICATION_DETAILS_SETTINGS")
                 .setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
                 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
-        startActivity(in);
+        startActivityAsUser(in, new UserHandle(UserHandle.getUserId(mLaunchedFromUid)));
     }
 
     private final class DisplayResolveInfo {
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index b016e99..1e268c4 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -18,16 +18,14 @@
 
 import android.net.Credentials;
 import android.net.LocalSocket;
-import android.os.Build;
 import android.os.Process;
+import android.os.SELinux;
 import android.os.SystemProperties;
 import android.util.Log;
 
 import dalvik.system.PathClassLoader;
 import dalvik.system.Zygote;
 
-import android.os.SELinux;
-
 import java.io.BufferedReader;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -234,9 +232,9 @@
                 ZygoteInit.setCloseOnExec(serverPipeFd, true);
             }
 
-            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
-                    parsedArgs.gids, parsedArgs.debugFlags, rlimits,
-                    parsedArgs.seInfo, parsedArgs.niceName);
+            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
+                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
+                    parsedArgs.niceName);
         } catch (IOException ex) {
             logAndPrintError(newStderr, "Exception creating pipe", ex);
         } catch (ErrnoException ex) {
@@ -341,6 +339,9 @@
          */
         int debugFlags;
 
+        /** From --mount-external */
+        int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
+
         /** from --target-sdk-version. */
         int targetSdkVersion;
         boolean targetSdkVersionSpecified;
@@ -526,6 +527,10 @@
                                 "Duplicate arg specified");
                     }
                     niceName = arg.substring(arg.indexOf('=') + 1);
+                } else if (arg.equals("--mount-external-singleuser")) {
+                    mountExternal = Zygote.MOUNT_EXTERNAL_SINGLEUSER;
+                } else if (arg.equals("--mount-external-multiuser")) {
+                    mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
                 } else {
                     break;
                 }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 6ad67c3..9e43749 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -16,16 +16,17 @@
 
 package com.android.internal.os;
 
+import static libcore.io.OsConstants.S_IRWXG;
+import static libcore.io.OsConstants.S_IRWXO;
+
 import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.net.LocalServerSocket;
 import android.os.Debug;
-import android.os.FileUtils;
 import android.os.Process;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.util.EventLog;
 import android.util.Log;
 
@@ -33,6 +34,7 @@
 import dalvik.system.Zygote;
 
 import libcore.io.IoUtils;
+import libcore.io.Libcore;
 
 import java.io.BufferedReader;
 import java.io.FileDescriptor;
@@ -452,7 +454,7 @@
         closeServerSocket();
 
         // set umask to 0077 so new files and directories will default to owner-only permissions.
-        FileUtils.setUMask(FileUtils.S_IRWXG | FileUtils.S_IRWXO);
+        Libcore.os.umask(S_IRWXG | S_IRWXO);
 
         if (parsedArgs.niceName != null) {
             Process.setArgV0(parsedArgs.niceName);
diff --git a/core/java/com/android/internal/statusbar/StatusBarNotification.java b/core/java/com/android/internal/statusbar/StatusBarNotification.java
index d443523..cb87ac4 100644
--- a/core/java/com/android/internal/statusbar/StatusBarNotification.java
+++ b/core/java/com/android/internal/statusbar/StatusBarNotification.java
@@ -19,6 +19,7 @@
 import android.app.Notification;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.widget.RemoteViews;
 
 
@@ -132,6 +133,11 @@
         return ((notification.flags & Notification.FLAG_ONGOING_EVENT) == 0)
                 && ((notification.flags & Notification.FLAG_NO_CLEAR) == 0);
     }
+
+    /** Returns a userHandle for the instance of the app that posted this notification. */
+    public int getUserId() {
+        return UserHandle.getUserId(this.uid);
+    }
 }
 
 
diff --git a/core/java/com/android/internal/view/RotationPolicy.java b/core/java/com/android/internal/view/RotationPolicy.java
index af512a3..98beadb 100644
--- a/core/java/com/android/internal/view/RotationPolicy.java
+++ b/core/java/com/android/internal/view/RotationPolicy.java
@@ -27,6 +27,7 @@
 import android.util.Log;
 import android.view.IWindowManager;
 import android.view.Surface;
+import android.view.WindowManagerGlobal;
 
 /**
  * Provides helper functions for configuring the display rotation policy.
@@ -79,8 +80,7 @@
             @Override
             public void run() {
                 try {
-                    IWindowManager wm = IWindowManager.Stub.asInterface(
-                            ServiceManager.getService(Context.WINDOW_SERVICE));
+                    IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
                     if (enabled) {
                         wm.freezeRotation(-1);
                     } else {
@@ -107,8 +107,7 @@
             @Override
             public void run() {
                 try {
-                    IWindowManager wm = IWindowManager.Stub.asInterface(
-                            ServiceManager.getService(Context.WINDOW_SERVICE));
+                    IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
                     if (enabled) {
                         wm.freezeRotation(Surface.ROTATION_0);
                     } else {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f77e8f3..4777c16 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -34,7 +34,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.os.storage.IMountService;
 import android.provider.Settings;
 import android.security.KeyStore;
@@ -246,7 +246,7 @@
         if (callingUid == android.os.Process.SYSTEM_UID) {
             return mCurrentUserId;
         } else {
-            return UserId.getUserId(callingUid);
+            return UserHandle.getUserId(callingUid);
         }
     }
 
diff --git a/core/java/com/android/internal/widget/LockSettingsService.java b/core/java/com/android/internal/widget/LockSettingsService.java
index 2fb81ac..350e006 100644
--- a/core/java/com/android/internal/widget/LockSettingsService.java
+++ b/core/java/com/android/internal/widget/LockSettingsService.java
@@ -25,7 +25,7 @@
 import android.os.Binder;
 import android.os.RemoteException;
 import android.os.SystemProperties;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.text.TextUtils;
@@ -97,7 +97,7 @@
 
     private static final void checkWritePermission(int userId) {
         final int callingUid = Binder.getCallingUid();
-        if (UserId.getAppId(callingUid) != android.os.Process.SYSTEM_UID) {
+        if (UserHandle.getAppId(callingUid) != android.os.Process.SYSTEM_UID) {
             throw new SecurityException("uid=" + callingUid
                     + " not authorized to write lock settings");
         }
@@ -105,7 +105,7 @@
 
     private static final void checkPasswordReadPermission(int userId) {
         final int callingUid = Binder.getCallingUid();
-        if (UserId.getAppId(callingUid) != android.os.Process.SYSTEM_UID) {
+        if (UserHandle.getAppId(callingUid) != android.os.Process.SYSTEM_UID) {
             throw new SecurityException("uid=" + callingUid
                     + " not authorized to read lock password");
         }
@@ -113,8 +113,8 @@
 
     private static final void checkReadPermission(int userId) {
         final int callingUid = Binder.getCallingUid();
-        if (UserId.getAppId(callingUid) != android.os.Process.SYSTEM_UID
-                && UserId.getUserId(callingUid) != userId) {
+        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);
         }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index b1423ca..f950d3d 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -67,7 +67,6 @@
 	android_os_ParcelFileDescriptor.cpp \
 	android_os_Parcel.cpp \
 	android_os_SELinux.cpp \
-	android_os_StatFs.cpp \
 	android_os_SystemClock.cpp \
 	android_os_SystemProperties.cpp \
 	android_os_Trace.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c936b0b..0c88297 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -134,7 +134,6 @@
 extern int register_android_os_Parcel(JNIEnv* env);
 extern int register_android_os_ParcelFileDescriptor(JNIEnv *env);
 extern int register_android_os_SELinux(JNIEnv* env);
-extern int register_android_os_StatFs(JNIEnv *env);
 extern int register_android_os_SystemProperties(JNIEnv *env);
 extern int register_android_os_SystemClock(JNIEnv* env);
 extern int register_android_os_Trace(JNIEnv* env);
@@ -1142,7 +1141,6 @@
     REG_JNI(register_android_os_MessageQueue),
     REG_JNI(register_android_os_ParcelFileDescriptor),
     REG_JNI(register_android_os_SELinux),
-    REG_JNI(register_android_os_StatFs),
     REG_JNI(register_android_os_Trace),
     REG_JNI(register_android_os_UEventObserver),
     REG_JNI(register_android_net_LocalSocketImpl),
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index a65262c..edc9732 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -22,6 +22,7 @@
 #include "jni.h"
 #include "GraphicsJNI.h"
 #include <android_runtime/AndroidRuntime.h>
+#include <ScopedUtfChars.h>
 
 #include "SkBlurDrawLooper.h"
 #include "SkColorFilter.h"
@@ -30,6 +31,7 @@
 #include "SkShader.h"
 #include "SkTypeface.h"
 #include "SkXfermode.h"
+#include "unicode/uloc.h"
 #include "unicode/ushape.h"
 #include "TextLayout.h"
 
@@ -254,11 +256,51 @@
         obj->setTextAlign(align);
     }
 
+    // generate bcp47 identifier for the supplied locale
+    static void toLanguageTag(char* output, size_t outSize,
+            const char* locale) {
+        if (output == NULL || outSize <= 0) {
+            return;
+        }
+        if (locale == NULL) {
+            output[0] = '\0';
+            return;
+        }
+        char canonicalChars[ULOC_FULLNAME_CAPACITY];
+        UErrorCode uErr = U_ZERO_ERROR;
+        uloc_canonicalize(locale, canonicalChars, ULOC_FULLNAME_CAPACITY,
+                &uErr);
+        if (U_SUCCESS(uErr)) {
+            char likelyChars[ULOC_FULLNAME_CAPACITY];
+            uErr = U_ZERO_ERROR;
+            uloc_addLikelySubtags(canonicalChars, likelyChars,
+                    ULOC_FULLNAME_CAPACITY, &uErr);
+            if (U_SUCCESS(uErr)) {
+                uErr = U_ZERO_ERROR;
+                uloc_toLanguageTag(likelyChars, output, outSize, FALSE, &uErr);
+                if (U_SUCCESS(uErr)) {
+                    return;
+                } else {
+                    ALOGD("uloc_toLanguageTag(\"%s\") failed: %s", likelyChars,
+                            u_errorName(uErr));
+                }
+            } else {
+                ALOGD("uloc_addLikelySubtags(\"%s\") failed: %s",
+                        canonicalChars, u_errorName(uErr));
+            }
+        } else {
+            ALOGD("uloc_canonicalize(\"%s\") failed: %s", locale,
+                    u_errorName(uErr));
+        }
+        // unable to build a proper language identifier
+        output[0] = '\0';
+    }
+
     static void setTextLocale(JNIEnv* env, jobject clazz, SkPaint* obj, jstring locale) {
-        const char* localeArray = env->GetStringUTFChars(locale, NULL);
-        SkString skLocale(localeArray);
-        obj->setTextLocale(skLocale);
-        env->ReleaseStringUTFChars(locale, localeArray);
+        ScopedUtfChars localeChars(env, locale);
+        char langTag[ULOC_FULLNAME_CAPACITY];
+        toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, localeChars.c_str());
+        obj->setLanguage(SkLanguage(langTag));
     }
 
     static jfloat getTextSize(JNIEnv* env, jobject paint) {
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 9b9b991..7abfcf1 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -19,6 +19,7 @@
 #include "TextLayoutCache.h"
 #include "TextLayout.h"
 #include "SkFontHost.h"
+#include "SkTypeface_android.h"
 #include <unicode/unistr.h>
 #include <unicode/normlzr.h>
 #include <unicode/uchar.h>
@@ -224,7 +225,7 @@
  */
 TextLayoutCacheKey::TextLayoutCacheKey(): text(NULL), start(0), count(0), contextCount(0),
         dirFlags(0), typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
-        hinting(SkPaint::kNo_Hinting)  {
+        hinting(SkPaint::kNo_Hinting), variant(SkPaint::kDefault_Variant), language()  {
 }
 
 TextLayoutCacheKey::TextLayoutCacheKey(const SkPaint* paint, const UChar* text,
@@ -237,6 +238,8 @@
     textScaleX = paint->getTextScaleX();
     flags = paint->getFlags();
     hinting = paint->getHinting();
+    variant = paint->getFontVariant();
+    language = paint->getLanguage();
 }
 
 TextLayoutCacheKey::TextLayoutCacheKey(const TextLayoutCacheKey& other) :
@@ -251,7 +254,9 @@
         textSkewX(other.textSkewX),
         textScaleX(other.textScaleX),
         flags(other.flags),
-        hinting(other.hinting) {
+        hinting(other.hinting),
+        variant(other.variant),
+        language(other.language) {
     if (other.text) {
         textCopy.setTo(other.text, other.contextCount);
     }
@@ -288,6 +293,12 @@
     deltaInt = lhs.dirFlags - rhs.dirFlags;
     if (deltaInt) return (deltaInt);
 
+    deltaInt = lhs.variant - rhs.variant;
+    if (deltaInt) return (deltaInt);
+
+    if (lhs.language < rhs.language) return -1;
+    if (lhs.language > rhs.language) return +1;
+
     return memcmp(lhs.getText(), rhs.getText(), lhs.contextCount * sizeof(UChar));
 }
 
@@ -615,6 +626,8 @@
     mShapingPaint.setTextScaleX(paint->getTextScaleX());
     mShapingPaint.setFlags(paint->getFlags());
     mShapingPaint.setHinting(paint->getHinting());
+    mShapingPaint.setFontVariant(paint->getFontVariant());
+    mShapingPaint.setLanguage(paint->getLanguage());
 
     // Split the BiDi run into Script runs. Harfbuzz will populate the pos, length and script
     // into the shaperItem
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index f007f9a..64b33a0 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -32,7 +32,7 @@
 #include <SkTemplates.h>
 #include <SkUtils.h>
 #include <SkAutoKern.h>
-#include "SkTypeface_android.h"
+#include <SkLanguage.h>
 
 #include <unicode/ubidi.h>
 #include <unicode/ushape.h>
@@ -102,6 +102,8 @@
     SkScalar textScaleX;
     uint32_t flags;
     SkPaint::Hinting hinting;
+    SkPaint::FontVariant variant;
+    SkLanguage language;
 
     inline const UChar* getText() const { return text ? text : textCopy.string(); }
 
diff --git a/core/jni/android_os_FileUtils.cpp b/core/jni/android_os_FileUtils.cpp
index 8d65cbc..a07f5b7 100644
--- a/core/jni/android_os_FileUtils.cpp
+++ b/core/jni/android_os_FileUtils.cpp
@@ -33,19 +33,6 @@
 
 namespace android {
 
-static jfieldID gFileStatusDevFieldID;
-static jfieldID gFileStatusInoFieldID;
-static jfieldID gFileStatusModeFieldID;
-static jfieldID gFileStatusNlinkFieldID;
-static jfieldID gFileStatusUidFieldID;
-static jfieldID gFileStatusGidFieldID;
-static jfieldID gFileStatusSizeFieldID;
-static jfieldID gFileStatusBlksizeFieldID;
-static jfieldID gFileStatusBlocksFieldID;
-static jfieldID gFileStatusAtimeFieldID;
-static jfieldID gFileStatusMtimeFieldID;
-static jfieldID gFileStatusCtimeFieldID;
-
 jint android_os_FileUtils_setPermissions(JNIEnv* env, jobject clazz,
                                          jstring file, jint mode,
                                          jint uid, jint gid)
@@ -68,44 +55,6 @@
     return chmod(file8.string(), mode) == 0 ? 0 : errno;
 }
 
-jint android_os_FileUtils_getPermissions(JNIEnv* env, jobject clazz,
-                                         jstring file, jintArray outArray)
-{
-    const jchar* str = env->GetStringCritical(file, 0);
-    String8 file8;
-    if (str) {
-        file8 = String8(str, env->GetStringLength(file));
-        env->ReleaseStringCritical(file, str);
-    }
-    if (file8.size() <= 0) {
-        return ENOENT;
-    }
-    struct stat st;
-    if (stat(file8.string(), &st) != 0) {
-        return errno;
-    }
-    jint* array = (jint*)env->GetPrimitiveArrayCritical(outArray, 0);
-    if (array) {
-        int len = env->GetArrayLength(outArray);
-        if (len >= 1) {
-            array[0] = st.st_mode;
-        }
-        if (len >= 2) {
-            array[1] = st.st_uid;
-        }
-        if (len >= 3) {
-            array[2] = st.st_gid;
-        }
-    }
-    env->ReleasePrimitiveArrayCritical(outArray, array, 0);
-    return 0;
-}
-
-jint android_os_FileUtils_setUMask(JNIEnv* env, jobject clazz, jint mask)
-{
-    return umask(mask);
-}
-
 jint android_os_FileUtils_getFatVolumeId(JNIEnv* env, jobject clazz, jstring path)
 {
     if (path == NULL) {
@@ -127,63 +76,15 @@
     return result;
 }
 
-jboolean android_os_FileUtils_getFileStatus(JNIEnv* env, jobject clazz, jstring path, jobject fileStatus) {
-    const char* pathStr = env->GetStringUTFChars(path, NULL);
-    jboolean ret = false;
-
-    struct stat s;
-    int res = stat(pathStr, &s);
-    if (res == 0) {
-        ret = true;
-        if (fileStatus != NULL) {
-            env->SetIntField(fileStatus, gFileStatusDevFieldID, s.st_dev);
-            env->SetIntField(fileStatus, gFileStatusInoFieldID, s.st_ino);
-            env->SetIntField(fileStatus, gFileStatusModeFieldID, s.st_mode);
-            env->SetIntField(fileStatus, gFileStatusNlinkFieldID, s.st_nlink);
-            env->SetIntField(fileStatus, gFileStatusUidFieldID, s.st_uid);
-            env->SetIntField(fileStatus, gFileStatusGidFieldID, s.st_gid);
-            env->SetLongField(fileStatus, gFileStatusSizeFieldID, s.st_size);
-            env->SetIntField(fileStatus, gFileStatusBlksizeFieldID, s.st_blksize);
-            env->SetLongField(fileStatus, gFileStatusBlocksFieldID, s.st_blocks);
-            env->SetLongField(fileStatus, gFileStatusAtimeFieldID, s.st_atime);
-            env->SetLongField(fileStatus, gFileStatusMtimeFieldID, s.st_mtime);
-            env->SetLongField(fileStatus, gFileStatusCtimeFieldID, s.st_ctime);
-        }
-    }
-
-    env->ReleaseStringUTFChars(path, pathStr);
-
-    return ret;
-}
-
 static const JNINativeMethod methods[] = {
     {"setPermissions",  "(Ljava/lang/String;III)I", (void*)android_os_FileUtils_setPermissions},
-    {"getPermissions",  "(Ljava/lang/String;[I)I", (void*)android_os_FileUtils_getPermissions},
-    {"setUMask",        "(I)I",                    (void*)android_os_FileUtils_setUMask},
     {"getFatVolumeId",  "(Ljava/lang/String;)I", (void*)android_os_FileUtils_getFatVolumeId},
-    {"getFileStatusNative", "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z", (void*)android_os_FileUtils_getFileStatus},
 };
 
 static const char* const kFileUtilsPathName = "android/os/FileUtils";
 
 int register_android_os_FileUtils(JNIEnv* env)
 {
-    jclass fileStatusClass = env->FindClass("android/os/FileUtils$FileStatus");
-    LOG_FATAL_IF(fileStatusClass == NULL, "Unable to find class android.os.FileUtils$FileStatus");
-
-    gFileStatusDevFieldID = env->GetFieldID(fileStatusClass, "dev", "I");
-    gFileStatusInoFieldID = env->GetFieldID(fileStatusClass, "ino", "I");
-    gFileStatusModeFieldID = env->GetFieldID(fileStatusClass, "mode", "I");
-    gFileStatusNlinkFieldID = env->GetFieldID(fileStatusClass, "nlink", "I");
-    gFileStatusUidFieldID = env->GetFieldID(fileStatusClass, "uid", "I");
-    gFileStatusGidFieldID = env->GetFieldID(fileStatusClass, "gid", "I");
-    gFileStatusSizeFieldID = env->GetFieldID(fileStatusClass, "size", "J");
-    gFileStatusBlksizeFieldID = env->GetFieldID(fileStatusClass, "blksize", "I");
-    gFileStatusBlocksFieldID = env->GetFieldID(fileStatusClass, "blocks", "J");
-    gFileStatusAtimeFieldID = env->GetFieldID(fileStatusClass, "atime", "J");
-    gFileStatusMtimeFieldID = env->GetFieldID(fileStatusClass, "mtime", "J");
-    gFileStatusCtimeFieldID = env->GetFieldID(fileStatusClass, "ctime", "J");
-
     return AndroidRuntime::registerNativeMethods(
         env, kFileUtilsPathName,
         methods, NELEM(methods));
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index 40443ff..e813c38 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -1,3 +1,19 @@
+/*
+ * 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.
+ */
+
 #define LOG_TAG "SELinuxJNI"
 #include <utils/Log.h>
 
@@ -6,6 +22,7 @@
 #include "android_runtime/AndroidRuntime.h"
 #ifdef HAVE_SELINUX
 #include "selinux/selinux.h"
+#include "selinux/android.h"
 #endif
 #include <errno.h>
 
@@ -458,6 +475,27 @@
   }
 
   /*
+   * Function: native_restorecon
+   * Purpose: restore default SELinux security context
+   * Parameters: pathname: the pathname for the file to be relabeled
+   * Returns: boolean: (true) file label successfully restored, (false) otherwise
+   * Exceptions: none
+   */
+  static jboolean native_restorecon(JNIEnv *env, jobject clazz, jstring pathname) {
+#ifdef HAVE_SELINUX
+    if (isSELinuxDisabled)
+      return true;
+
+    const char *file = const_cast<char *>(env->GetStringUTFChars(pathname, NULL));
+    int ret = selinux_android_restorecon(file);
+    env->ReleaseStringUTFChars(pathname, file);
+    return (ret == 0);
+#else
+    return true;
+#endif
+  }
+
+  /*
    * JNI registration.
    */
   static JNINativeMethod method_table[] = {
@@ -472,6 +510,7 @@
     { "getPidContext"            , "(I)Ljava/lang/String;"                        , (void*)getPidCon        },
     { "isSELinuxEnforced"        , "()Z"                                          , (void*)isSELinuxEnforced},
     { "isSELinuxEnabled"         , "()Z"                                          , (void*)isSELinuxEnabled },
+    { "native_restorecon"        , "(Ljava/lang/String;)Z"                        , (void*)native_restorecon},
     { "setBooleanValue"          , "(Ljava/lang/String;Z)Z"                       , (void*)setBooleanValue  },
     { "setFileContext"           , "(Ljava/lang/String;Ljava/lang/String;)Z"      , (void*)setFileCon       },
     { "setFSCreateContext"       , "(Ljava/lang/String;)Z"                        , (void*)setFSCreateCon   },
diff --git a/core/jni/android_os_StatFs.cpp b/core/jni/android_os_StatFs.cpp
deleted file mode 100644
index 79d8fef..0000000
--- a/core/jni/android_os_StatFs.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright 2007, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#if INCLUDE_SYS_MOUNT_FOR_STATFS
-#include <sys/mount.h>
-#else
-#include <sys/statfs.h>
-#endif
-
-#include <errno.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
-
-
-namespace android
-{
-
-// ----------------------------------------------------------------------------
-
-struct fields_t {
-    jfieldID    context;
-};
-static fields_t fields;
-
-// ----------------------------------------------------------------------------
-
-static jint
-android_os_StatFs_getBlockSize(JNIEnv *env, jobject thiz)
-{
-    struct statfs *stat = (struct statfs *)env->GetIntField(thiz, fields.context);
-    return stat->f_bsize;
-}
-
-static jint
-android_os_StatFs_getBlockCount(JNIEnv *env, jobject thiz)
-{
-    struct statfs *stat = (struct statfs *)env->GetIntField(thiz, fields.context);
-    return stat->f_blocks;
-}
-
-static jint
-android_os_StatFs_getFreeBlocks(JNIEnv *env, jobject thiz)
-{
-    struct statfs *stat = (struct statfs *)env->GetIntField(thiz, fields.context);
-    return stat->f_bfree;
-}
-
-static jint
-android_os_StatFs_getAvailableBlocks(JNIEnv *env, jobject thiz)
-{
-    struct statfs *stat = (struct statfs *)env->GetIntField(thiz, fields.context);
-    return stat->f_bavail;
-}
-
-static void
-android_os_StatFs_native_restat(JNIEnv *env, jobject thiz, jstring path)
-{
-    if (path == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return;
-    }
-
-    // get the object handle
-    struct statfs *stat = (struct statfs *)env->GetIntField(thiz, fields.context);
-    if (stat == NULL) {
-        jniThrowException(env, "java/lang/NoSuchFieldException", NULL);
-        return;
-    }
-
-    const char* pathstr = env->GetStringUTFChars(path, NULL);
-    if (pathstr == NULL) {
-        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
-        return;
-    }
-
-    // note that stat will contain the new file data corresponding to
-    // pathstr
-    if (statfs(pathstr, stat) != 0) {
-        ALOGE("statfs %s failed, errno: %d", pathstr, errno);
-        delete stat;
-        env->SetIntField(thiz, fields.context, 0);
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-    }
-    // Release pathstr
-    env->ReleaseStringUTFChars(path, pathstr);
-}
-
-static void
-android_os_StatFs_native_setup(JNIEnv *env, jobject thiz, jstring path)
-{
-    if (path == NULL) {
-        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
-        return;
-    }
-
-    struct statfs* stat = new struct statfs;
-    if (stat == NULL) {
-        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
-        return;
-    }
-    env->SetIntField(thiz, fields.context, (int)stat);
-    android_os_StatFs_native_restat(env, thiz, path);
-}
-
-static void
-android_os_StatFs_native_finalize(JNIEnv *env, jobject thiz)
-{
-    struct statfs *stat = (struct statfs *)env->GetIntField(thiz, fields.context);
-    if (stat != NULL) {
-        delete stat;
-        env->SetIntField(thiz, fields.context, 0);
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-static JNINativeMethod gMethods[] = {
-    {"getBlockSize",       "()I",                       (void *)android_os_StatFs_getBlockSize},
-    {"getBlockCount",      "()I",                       (void *)android_os_StatFs_getBlockCount},
-    {"getFreeBlocks",      "()I",                       (void *)android_os_StatFs_getFreeBlocks},
-    {"getAvailableBlocks", "()I",                       (void *)android_os_StatFs_getAvailableBlocks},
-    {"native_setup",       "(Ljava/lang/String;)V",     (void *)android_os_StatFs_native_setup},
-    {"native_finalize",    "()V",                       (void *)android_os_StatFs_native_finalize},
-    {"native_restat",      "(Ljava/lang/String;)V",     (void *)android_os_StatFs_native_restat},
-};
-
-
-int register_android_os_StatFs(JNIEnv *env)
-{
-    jclass clazz;
-
-    clazz = env->FindClass("android/os/StatFs");
-    if (clazz == NULL) {
-        ALOGE("Can't find android/os/StatFs");
-        return -1;
-    }
-
-    fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
-    if (fields.context == NULL) {
-        ALOGE("Can't find StatFs.mNativeContext");
-        return -1;
-    }
-
-    return AndroidRuntime::registerNativeMethods(env,
-            "android/os/StatFs", gMethods, NELEM(gMethods));
-}
-
-}   // namespace android
diff --git a/core/jni/android_util_FloatMath.cpp b/core/jni/android_util_FloatMath.cpp
index e30756b..73b7a6f 100644
--- a/core/jni/android_util_FloatMath.cpp
+++ b/core/jni/android_util_FloatMath.cpp
@@ -29,6 +29,14 @@
     static float ExpF(JNIEnv* env, jobject clazz, float x) {
         return expf(x);
     }
+
+    static float PowF(JNIEnv* env, jobject clazz, float x, float y) {
+        return powf(x, y);
+    }
+
+    static float HypotF(JNIEnv* env, jobject clazz, float x, float y) {
+        return hypotf(x, y);
+    }
 };
 
 static JNINativeMethod gMathUtilsMethods[] = {
@@ -38,6 +46,8 @@
     {"cos", "(F)F", (void*) MathUtilsGlue::CosF},
     {"sqrt", "(F)F", (void*) MathUtilsGlue::SqrtF},
     {"exp", "(F)F", (void*) MathUtilsGlue::ExpF},
+    {"pow", "(FF)F", (void*) MathUtilsGlue::PowF},
+    {"hypot", "(FF)F", (void*) MathUtilsGlue::HypotF},
 };
 
 int register_android_util_FloatMath(JNIEnv* env)
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 3ad6406..bada329 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -221,7 +221,7 @@
 static void Surface_init(
         JNIEnv* env, jobject clazz,
         jobject session,
-        jint, jstring jname, jint dpy, jint w, jint h, jint format, jint flags)
+        jint, jstring jname, jint layerStack, jint w, jint h, jint format, jint flags)
 {
     if (session == NULL) {
         doThrowNPE(env);
@@ -233,12 +233,12 @@
 
     sp<SurfaceControl> surface;
     if (jname == NULL) {
-        surface = client->createSurface(dpy, w, h, format, flags);
+        surface = client->createSurface(layerStack, w, h, format, flags);
     } else {
         const jchar* str = env->GetStringCritical(jname, 0);
         const String8 name(str, env->GetStringLength(jname));
         env->ReleaseStringCritical(jname, str);
-        surface = client->createSurface(name, dpy, w, h, format, flags);
+        surface = client->createSurface(name, layerStack, w, h, format, flags);
     }
 
     if (surface == 0) {
@@ -717,7 +717,7 @@
     }
 }
 
-static void Surface_setDisplayId(JNIEnv* env, jobject thiz, jint displayId)
+static void Surface_setLayerStack(JNIEnv* env, jobject thiz, jint layerStack)
 {
     const sp<SurfaceControl>& surface(getSurfaceControl(env, thiz));
     if (surface == 0) return;
@@ -863,7 +863,7 @@
     {"writeToParcel",       "(Landroid/os/Parcel;I)V", (void*)Surface_writeToParcel },
     {"isConsumerRunningBehind", "()Z", (void*)Surface_isConsumerRunningBehind },
     {"setWindowCrop",       "(Landroid/graphics/Rect;)V", (void*)Surface_setWindowCrop },
-    {"setDisplayId",        "(I)V", (void*)Surface_setDisplayId },
+    {"setLayerStack",        "(I)V", (void*)Surface_setLayerStack },
 };
 
 void nativeClassInit(JNIEnv* env, jclass clazz)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 195b1ef..1c9b440 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -283,7 +283,7 @@
     <!-- @hide -->
     <permission android:name="android.permission.BIND_DIRECTORY_SEARCH"
         android:permissionGroup="android.permission-group.PERSONAL_INFO"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to read the user's call log. -->
     <permission android:name="android.permission.READ_CALL_LOG"
@@ -766,7 +766,6 @@
         android:protectionLevel="dangerous"
         android:label="@string/permlab_getTasks"
         android:description="@string/permdesc_getTasks" />
-
     <!-- Allows an application to call APIs that allow it to do interactions
          across the users on the device, using singleton services and
          user-targeted broadcasts.  This permission is not available to
@@ -786,6 +785,15 @@
         android:label="@string/permlab_interactAcrossUsersFull"
         android:description="@string/permdesc_interactAcrossUsersFull" />
 
+    <!-- Allows an application to call APIs that allow it to query and manage
+         users on the device. This permission is not available to
+         third party applications. -->
+    <permission android:name="android.permission.MANAGE_USERS"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signature|system"
+        android:label="@string/permlab_manageUsers"
+        android:description="@string/permdesc_manageUsers" />
+    
     <!-- Allows an application to get full detailed information about
          recently running tasks, with full fidelity to the real state.
          @hide -->
diff --git a/core/res/res/raw-ar/loaderror.html b/core/res/res/raw-ar/loaderror.html
index aa9805c..5b88558 100644
--- a/core/res/res/raw-ar/loaderror.html
+++ b/core/res/res/raw-ar/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>صفحة الويب غير متوفرة</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; direction: rtl; }
diff --git a/core/res/res/raw-ar/nodomain.html b/core/res/res/raw-ar/nodomain.html
index 2e5849f..613c230 100644
--- a/core/res/res/raw-ar/nodomain.html
+++ b/core/res/res/raw-ar/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>صفحة الويب غير متوفرة</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; direction: rtl; }
diff --git a/core/res/res/raw-cs/loaderror.html b/core/res/res/raw-cs/loaderror.html
index ce88981..a07970b 100644
--- a/core/res/res/raw-cs/loaderror.html
+++ b/core/res/res/raw-cs/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Webov&aacute; str&aacute;nka nen&iacute; dostupn&aacute;</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-cs/nodomain.html b/core/res/res/raw-cs/nodomain.html
index 26479a9..bd78ca3 100644
--- a/core/res/res/raw-cs/nodomain.html
+++ b/core/res/res/raw-cs/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Webov&aacute; str&aacute;nka nen&iacute; dostupn&aacute;</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-da/loaderror.html b/core/res/res/raw-da/loaderror.html
index 12a75c6c..8065f1a 100644
--- a/core/res/res/raw-da/loaderror.html
+++ b/core/res/res/raw-da/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Websiden er ikke tilg&aelig;ngelig</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-da/nodomain.html b/core/res/res/raw-da/nodomain.html
index 3b8fe78..b24de2b 100644
--- a/core/res/res/raw-da/nodomain.html
+++ b/core/res/res/raw-da/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Websiden er ikke tilg&aelig;ngelig</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-de/loaderror.html b/core/res/res/raw-de/loaderror.html
index bece2d7..62d7a13 100644
--- a/core/res/res/raw-de/loaderror.html
+++ b/core/res/res/raw-de/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Webseite nicht verf&uuml;gbar</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-de/nodomain.html b/core/res/res/raw-de/nodomain.html
index 9fd8094..7ea8d86d 100644
--- a/core/res/res/raw-de/nodomain.html
+++ b/core/res/res/raw-de/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Webseite nicht verf&uuml;gbar</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-en-rGB/loaderror.html b/core/res/res/raw-en-rGB/loaderror.html
index 359a1e7..fd3d766 100644
--- a/core/res/res/raw-en-rGB/loaderror.html
+++ b/core/res/res/raw-en-rGB/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Web page not available</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-en-rGB/nodomain.html b/core/res/res/raw-en-rGB/nodomain.html
index 01dd603..4ca403b 100644
--- a/core/res/res/raw-en-rGB/nodomain.html
+++ b/core/res/res/raw-en-rGB/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Web page not available</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-es/loaderror.html b/core/res/res/raw-es/loaderror.html
index 8829bf5..0102b8a 100644
--- a/core/res/res/raw-es/loaderror.html
+++ b/core/res/res/raw-es/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>P&aacute;gina web no disponible</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-es/nodomain.html b/core/res/res/raw-es/nodomain.html
index a11333e..03a9855 100644
--- a/core/res/res/raw-es/nodomain.html
+++ b/core/res/res/raw-es/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>P&aacute;gina web no disponible</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-fi/loaderror.html b/core/res/res/raw-fi/loaderror.html
index 3b1ec97..2ef97f4 100644
--- a/core/res/res/raw-fi/loaderror.html
+++ b/core/res/res/raw-fi/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Verkkosivu ei ole k&auml;ytett&auml;viss&auml;</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-fi/nodomain.html b/core/res/res/raw-fi/nodomain.html
index 84fedb4..58abc2d 100644
--- a/core/res/res/raw-fi/nodomain.html
+++ b/core/res/res/raw-fi/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Verkkosivu ei ole k&auml;ytett&auml;viss&auml;</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-fr/loaderror.html b/core/res/res/raw-fr/loaderror.html
index f61f50b..f22d1b1 100644
--- a/core/res/res/raw-fr/loaderror.html
+++ b/core/res/res/raw-fr/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Page Web non disponible</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-fr/nodomain.html b/core/res/res/raw-fr/nodomain.html
index b3b93b3..3c62aee 100644
--- a/core/res/res/raw-fr/nodomain.html
+++ b/core/res/res/raw-fr/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Page Web non disponible</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-hu/loaderror.html b/core/res/res/raw-hu/loaderror.html
index 6b3d45e..4eccb24 100644
--- a/core/res/res/raw-hu/loaderror.html
+++ b/core/res/res/raw-hu/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>A weboldal nem &eacute;rhető el</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-hu/nodomain.html b/core/res/res/raw-hu/nodomain.html
index d3465ff..08399e2 100644
--- a/core/res/res/raw-hu/nodomain.html
+++ b/core/res/res/raw-hu/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>A weboldal nem &eacute;rhető el</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-it/loaderror.html b/core/res/res/raw-it/loaderror.html
index e81466a..9f78d08 100644
--- a/core/res/res/raw-it/loaderror.html
+++ b/core/res/res/raw-it/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Pagina web non disponibile</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-it/nodomain.html b/core/res/res/raw-it/nodomain.html
index a2321c7..6e1876c 100644
--- a/core/res/res/raw-it/nodomain.html
+++ b/core/res/res/raw-it/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Pagina web non disponibile</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-iw/loaderror.html b/core/res/res/raw-iw/loaderror.html
index 8d5a53f..08ff28e 100644
--- a/core/res/res/raw-iw/loaderror.html
+++ b/core/res/res/raw-iw/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>דף אינטרנט לא זמין</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; direction: rtl; }
diff --git a/core/res/res/raw-iw/nodomain.html b/core/res/res/raw-iw/nodomain.html
index 0dcd7f8..fd89aa0 100644
--- a/core/res/res/raw-iw/nodomain.html
+++ b/core/res/res/raw-iw/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>דף אינטרנט לא זמין</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; direction: rtl; }
diff --git a/core/res/res/raw-ja/loaderror.html b/core/res/res/raw-ja/loaderror.html
index 68e568b..819859e 100644
--- a/core/res/res/raw-ja/loaderror.html
+++ b/core/res/res/raw-ja/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>ページが見つかりませんでした</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-ja/nodomain.html b/core/res/res/raw-ja/nodomain.html
index 1dff1d4..75495db 100644
--- a/core/res/res/raw-ja/nodomain.html
+++ b/core/res/res/raw-ja/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>ページが見つかりませんでした</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-ko/loaderror.html b/core/res/res/raw-ko/loaderror.html
index 59f0f25..0ae687d 100644
--- a/core/res/res/raw-ko/loaderror.html
+++ b/core/res/res/raw-ko/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>웹페이지를 표시할 수 없습니다.</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-ko/nodomain.html b/core/res/res/raw-ko/nodomain.html
index 0eadc39..f014845 100644
--- a/core/res/res/raw-ko/nodomain.html
+++ b/core/res/res/raw-ko/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>웹페이지를 표시할 수 없습니다.</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-nl/loaderror.html b/core/res/res/raw-nl/loaderror.html
index 76bb07c..819c3ba 100644
--- a/core/res/res/raw-nl/loaderror.html
+++ b/core/res/res/raw-nl/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Webpagina niet beschikbaar</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-nl/nodomain.html b/core/res/res/raw-nl/nodomain.html
index ffac947..52c50e8 100644
--- a/core/res/res/raw-nl/nodomain.html
+++ b/core/res/res/raw-nl/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Webpagina niet beschikbaar</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-pl/loaderror.html b/core/res/res/raw-pl/loaderror.html
index 9cc1342..085d69d 100644
--- a/core/res/res/raw-pl/loaderror.html
+++ b/core/res/res/raw-pl/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Strona internetowa jest niedostępna</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-pl/nodomain.html b/core/res/res/raw-pl/nodomain.html
index 23f529d..c994abe 100644
--- a/core/res/res/raw-pl/nodomain.html
+++ b/core/res/res/raw-pl/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Strona internetowa jest niedostępna</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-pt-rBR/loaderror.html b/core/res/res/raw-pt-rBR/loaderror.html
index 3476239..9f363c5 100644
--- a/core/res/res/raw-pt-rBR/loaderror.html
+++ b/core/res/res/raw-pt-rBR/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>P&aacute;gina da web n&atilde;o dispon&iacute;vel</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-pt-rBR/nodomain.html b/core/res/res/raw-pt-rBR/nodomain.html
index 546c610..33b76f9 100644
--- a/core/res/res/raw-pt-rBR/nodomain.html
+++ b/core/res/res/raw-pt-rBR/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>P&aacute;gina da web n&atilde;o dispon&iacute;vel</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-rm/loaderror.html b/core/res/res/raw-rm/loaderror.html
index 8e4a3fe..e09ed49 100644
--- a/core/res/res/raw-rm/loaderror.html
+++ b/core/res/res/raw-rm/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Pagina d'internet betg disponibla</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-rm/nodomain.html b/core/res/res/raw-rm/nodomain.html
index 1e2833b..964f7f4 100644
--- a/core/res/res/raw-rm/nodomain.html
+++ b/core/res/res/raw-rm/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Pagina d'internet betg disponibla</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-ru/loaderror.html b/core/res/res/raw-ru/loaderror.html
index 5a0312e..8faf416 100644
--- a/core/res/res/raw-ru/loaderror.html
+++ b/core/res/res/raw-ru/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Веб-страница недоступна</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-ru/nodomain.html b/core/res/res/raw-ru/nodomain.html
index 86a42a1..3f606f9 100644
--- a/core/res/res/raw-ru/nodomain.html
+++ b/core/res/res/raw-ru/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Веб-страница недоступна</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-th/loaderror.html b/core/res/res/raw-th/loaderror.html
index 05310a7..7e12c57 100644
--- a/core/res/res/raw-th/loaderror.html
+++ b/core/res/res/raw-th/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>ไม่มีเว็บเพจนี้</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-th/nodomain.html b/core/res/res/raw-th/nodomain.html
index 37b8593..b94e4a9 100644
--- a/core/res/res/raw-th/nodomain.html
+++ b/core/res/res/raw-th/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>ไม่มีเว็บเพจนี้</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-tr/loaderror.html b/core/res/res/raw-tr/loaderror.html
index b6f4890..665c9a8 100644
--- a/core/res/res/raw-tr/loaderror.html
+++ b/core/res/res/raw-tr/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Web sayfası yok</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-tr/nodomain.html b/core/res/res/raw-tr/nodomain.html
index a79c21b..90545da 100644
--- a/core/res/res/raw-tr/nodomain.html
+++ b/core/res/res/raw-tr/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Web sayfası yok</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-zh-rCN/loaderror.html b/core/res/res/raw-zh-rCN/loaderror.html
index 809d31f..cab447b 100644
--- a/core/res/res/raw-zh-rCN/loaderror.html
+++ b/core/res/res/raw-zh-rCN/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>找不到网页</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-zh-rCN/nodomain.html b/core/res/res/raw-zh-rCN/nodomain.html
index eb03187..ba74131 100644
--- a/core/res/res/raw-zh-rCN/nodomain.html
+++ b/core/res/res/raw-zh-rCN/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>找不到网页</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-zh-rTW/loaderror.html b/core/res/res/raw-zh-rTW/loaderror.html
index 0b4695a..cb86ae6 100644
--- a/core/res/res/raw-zh-rTW/loaderror.html
+++ b/core/res/res/raw-zh-rTW/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>您所查詢的網頁不存在或已移除</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw-zh-rTW/nodomain.html b/core/res/res/raw-zh-rTW/nodomain.html
index 3577a9d..18d786c 100644
--- a/core/res/res/raw-zh-rTW/nodomain.html
+++ b/core/res/res/raw-zh-rTW/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>您所查詢的網頁不存在或已移除</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index e13921f..ad03dd2 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -156,7 +156,7 @@
     <string name="global_action_power_off" msgid="4471879440839879722">"Sit af"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Foutverslag"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Neem foutverslag"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"Dit sal inligting oor die huidige toestand van jou toestel insamel, om as \'n e-posboodskap te stuur. Dit sal \'n tydjie neem vandat die foutverslag begin is totdat dit reg is om gestuur te word; wees asseblief geduldig."</string>
+    <string name="bugreport_message" msgid="398447048750350456">"Dit sal inligting oor die huidige toestand van jou toestel insamel om as \'n e-posboodskap te stuur. Dit sal \'n tydjie neem vandat die foutverslag begin is totdat dit reg is om gestuur te word; wees asseblief geduldig."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Stilmodus"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Klank is AF"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Klank is AAN"</string>
@@ -224,6 +224,10 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Laat die program toe om aksies vir verskillende gebruikers op die toestel uit te voer. Kwaadwillige programme kan dit gebruik om die beskerming tussen gebruikers te skend."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"volle lisensie vir interaksie tussen gebruikers"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Laat alle moontlike interaksies tussen gebruikers toe."</string>
+    <!-- no translation found for permlab_manageUsers (1676150911672282428) -->
+    <skip />
+    <!-- no translation found for permdesc_manageUsers (8409306667645355638) -->
+    <skip />
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"haal besonderhede van lopende programme op"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Laat die program toe om inligting op te haal oor huidige en onlangse lopende take. Kwaadwillige programme kan dalk private inligting oor ander programme ontdek."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"herrangskik lopende programme"</string>
@@ -1309,4 +1313,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-oudio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Klaar"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index ef8f604..fc6d4b8 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"መተግበሪያው በመሣሪያው ላይ በተለያዩ ተጠቃሚዎች ላይ እርምጃዎችን እንዲፈጽም ይፈቅድለታል። ተንኮል-አዘል መተግበሪያዎች ይህንን ተጠቅመው በተጠቃሚዎች መካከል ያለውን ጥበቃ ሊጥሱ ይችላሉ።"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"በተለያዩ ተጠቃሚዎች መካከል መስተጋብር ለመፍጠር ሙሉ ፍቃድ"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"በተለያዩ ተጠቃሚዎች ላይ ሊኖሩ የሚችሉ መስተጋብሮችን ሁሉ ይፈቅዳል።"</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"ተጠቃሚዎችን ያስተዳድሩ"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"መተግበሪያዎች በመሣሪያዎች ላይ ያሉ ተጠቃሚዎችን እንዲያቀናብር ያስችለዋል፣ መጠየቅን፣ መፍጠርንና መሰረዝን ጨምሮ።"</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"እየሄዱ ስላሉ የመተግበሪያዎች ዝርዝሮች አምጣ"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"መተግበሪያው በአሁኑ ጊዜ እየተካሄዱ ስላሉና በቅርብ ጊዜ ስለተካሄዱ ተግባሮች መረጃ ዝርዝር እንዲያወጣ ይፈቅድለታል። ተንኮል-አዘል መተግበሪያዎች ስለ ሌሎች መተግበሪያዎች የግል መረጃ ሊያገኙ ይችላሉ።"</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"አሂድ ትግበራዎችን ድጋሚ ደርድር"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"የብሉቱዝ ድምጽ"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"ተከናውኗል"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"የሚዲያ ውጽዓት"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"ውስጥ የተሰራ ማያ ገጽ"</string>
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index bde732c1..14d95a5 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -156,7 +156,7 @@
     <string name="global_action_power_off" msgid="4471879440839879722">"إيقاف التشغيل"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"تقرير الأخطاء"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"إعداد تقرير بالأخطاء"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"سيجمع هذا معلومات حول حالة جهازك الحالي لإرسالها كرسالة إلكترونية. سيستغرق وقتًا قليلاً من بدء عرض تقرير بالأخطاء وحتى يكون جاهزًا للإرسال، الرجاء الانتظار."</string>
+    <string name="bugreport_message" msgid="398447048750350456">"سيجمع هذا معلومات حول حالة جهازك الحالي لإرسالها كرسالة إلكترونية، ولكنه سيستغرق وقتًا قليلاً من بدء عرض تقرير بالأخطاء. وحتى يكون جاهزًا للإرسال، الرجاء الانتظار."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"وضع صامت"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"الصوت متوقف"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"الصوت قيد التشغيل"</string>
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"للسماح للتطبيق بتنفيذ إجراءات بين مستخدمين مختلفين على الجهاز. قد تستخدم التطبيقات الضارة ذلك لانتهاك الحماية بين المستخدمين."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"الترخيص بالكامل للتعامل بين المستخدمين"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"للسماح بجميع التعاملات المحتملة بين المستخدمين."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"إدارة المستخدمين"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"لتمكين التطبيقات من إدارة المستخدمين على الجهاز، بما في ذلك طلب البحث والإنشاء والحذف."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"استرداد تفاصيل التطبيقات قيد التشغيل"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"يسمح للتطبيق باسترداد معلومات تفصيلية حول المهام قيد التشغيل حاليًا ومؤخرًا. قد تكتشف التطبيقات الضارة معلومات خاصة حول التطبيقات الأخرى."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"إعادة ترتيب التطبيقات قيد التشغيل"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"صوت بلوتوث"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"تم"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"المنفذ الإعلامي"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index b9b6cf3..d801628 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Дазваляе прыкладанню выконваць дзеяннi сярод розных карыстальнiкаў прылады. Шкоднасныя прыкладаннi могуць выкарыстоўваць гэта, каб парушыць абарону памiж карыстальнiкамi."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"поўная ліцэнзія для ўзаемадзеяння паміж карыстальнiкамi"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Дазваляе ўсе магчымыя ўзаемадзеяннi паміж карыстальнікамі."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"кіраванне дадзенымi карыстальнікаў"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Дазваляе прыкладанням кіраваць звесткамi карыстальнікаў на прыладзе, у тым ліку запытамi, працэсамi стварэння і выдалення."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"атрымаць падрабязныя дадзеныя пра запушчаныя прыкладаннi"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Дазваляе прыкладанню атрымліваць падрабязную інфармацыю пра бягучыя і нядаўна запушчаныя задачы. Шкоднасныя прыкладанні могуць атрымліваць асабістую інфармацыю пра іншыя прыкладаннi."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"змяніць парадак запушчаных прыкладанняў"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-аўдыё"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Гатова"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Мультымедыйны выхад"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Убудаваны экран"</string>
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 6370ed4..81ba8a7 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Разрешава на приложението да изпълнява действия за различни потребители на устройството. Злонамерените приложения може да използват това, за да нарушат защитата между потребителите."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"пълен лиценз за взаимодействие с потребителите"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Разрешава всички възможни взаимодействия с потребителите."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"управление на потребителите"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Разрешава на приложенията да управляват потребителите на устройството, включително изброяването, създаването и изтриването им."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"извличане на подробности за изпълняваните прилож."</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Разрешава на приложението да извлича подробна информация за задачите, изпълнявани понастоящем и неотдавна. Злонамерените приложения могат да открият поверителна информация за други приложения."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"пренареждане на изпълняваните приложения"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Звук през Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Изходяща мултимедия"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 9c6cca1..0781217 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permet que l\'aplicació dugui a terme accions en diferents usuaris del dispositiu. Les aplicacions malicioses poden fer servir aquest permís per infringir la protecció entre usuaris."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"llicència completa per interaccionar entre usuaris"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Permet totes les interaccions possibles entre usuaris."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"gestió d\'usuaris"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Permet que les aplicacions gestionin usuaris al dispositiu, incloses les consultes, la creació i la supressió."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"recupera els detalls d\'aplicacions en execució"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Permet que l\'aplicació recuperi informació detallada sobre les tasques que s\'estan executant actualment i que s\'han executat recentment. Les aplicacions malicioses poden descobrir informació privada sobre altres aplicacions."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"canvia l\'ordre de les aplicacions en execució"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Àudio per Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fet"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Sortida de contingut multimèdia"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Pantalla integrada"</string>
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 898fe14..4e7da84 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Umožňuje aplikaci provádět akce napříč různými uživateli zařízení. Škodlivé aplikace toto oprávnění mohou zneužít k obejití ochrany mezi uživateli."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"úplné oprávnění k interakcím napříč uživateli"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Povoluje všechny možné interakce napříč uživateli."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"správa uživatelů"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Umožňuje aplikacím spravovat uživatele v zařízení, včetně vytváření a mazání dotazů."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"získání podrobností o spuštěných aplikacích"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Umožňuje aplikaci získat podrobné informace o aktuálně a naposledy spuštěných úlohách. Škodlivé aplikace mohou odhalit soukromé informace o ostatních aplikacích."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"změna uspořádání spuštěných aplikací"</string>
@@ -842,7 +844,7 @@
     <item quantity="other" msgid="3903706804349556379">"před <xliff:g id="COUNT">%d</xliff:g> s"</item>
   </plurals>
   <plurals name="num_minutes_ago">
-    <item quantity="one" msgid="3306787433088810191">"před 1 minutou"</item>
+    <item quantity="one" msgid="3306787433088810191">"před 1 min"</item>
     <item quantity="other" msgid="2176942008915455116">"před <xliff:g id="COUNT">%d</xliff:g> min"</item>
   </plurals>
   <plurals name="num_hours_ago">
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth Audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 9ccf3f0..ea40879 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Tillader, at appen udfører handlinger på tværs af forskellige brugere på enheden. Ondsindede apps kan bruge dette til at krænke beskyttelsen mellem brugere."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"fuld licens til at kommunikere på tværs af brugere"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Tillader alle mulige former for kommunikation på tværs af brugere."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"administrer brugere"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Tillader, at apps administrerer brugere på enheden, herunder forespørgsler, oprettelser og sletninger."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"hente oplysninger om apps, der kører"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Tillader, at appen kan hente oplysninger om aktuelle og seneste opgaver. Ondsindede apps kan muligvis finde personlige oplysninger om andre apps."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"omorganisere kørende apps"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Udfør"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieudgang"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Indbygget skærm"</string>
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 596e8f5..a0280c8 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -156,7 +156,7 @@
     <string name="global_action_power_off" msgid="4471879440839879722">"Ausschalten"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Fehlerbericht"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Fehlerbericht abrufen"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"Bei diesem Fehlerbericht werden Daten zum aktuellen Status Ihres Geräts erfasst und als E-Mail versandt. Vom Start des Berichts bis zu seinem Versand kann es eine Weile dauern. Bitte haben Sie Geduld."</string>
+    <string name="bugreport_message" msgid="398447048750350456">"Bei diesem Fehlerbericht werden Daten zum aktuellen Status Ihres Geräts erfasst und als E-Mail versandt. Vom Start des Berichts bis zu seinem Versand kann es eine Weile dauern. Bitte haben Sie etwas Geduld."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Lautlos-Modus"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ton ist AUS."</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ton ist AN."</string>
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Ermöglicht der App, auf dem Gerät nutzerübergreifend Aktionen durchzuführen. Schädliche Apps können so den zwischen den Nutzern bestehenden Schutz aufheben."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"Vollständige Lizenz zum nutzerübergreifenden Interagieren"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Ermöglicht alle möglichen nutzerübergreifenden Interaktionen"</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"Nutzer verwalten"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Ermöglicht Apps die Verwaltung der Nutzer auf dem Gerät, unter anderem das Abfragen, Erstellen und Löschen von Nutzern"</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"Details zu ausgeführten Apps abrufen"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Ermöglicht der App, detaillierte Informationen zu aktuellen und kürzlich ausgeführten Aufgaben abzurufen. Schädliche Apps können so geheime Informationen zu anderen Apps erhalten."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"Aktive Apps neu ordnen"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-Audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fertig"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medienausgabe"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Integrierter Bildschirm"</string>
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 95717a2..82f0c62 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Δίνει στην εφαρμογή τη δυνατότητα να πραγματοποιεί ενέργειες σε όλους τους διαφορετικούς χρήστες στη συσκευή. Οι κακόβουλες εφαρμογές ενδέχεται να χρησιμοποιήσουν αυτή τη δυνατότητα για να παραβιάσουν την προστασία μεταξύ των χρηστών."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"πλήρης άδεια αλληλεπίδρασης στους χρήστες"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Επιτρέπει όλες τις πιθανές αλληλεπιδράσεις στους χρήστες."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"διαχείριση χρηστών"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Επιτρέπει στις εφαρμογές να διαχειρίζονται τους χρήστες της συσκευής, συμπεριλαμβανομένων των ερωτημάτων της δημιουργίας και της διαγραφής."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"ανάκτηση λεπτομερειών σχετικά με τις εκτελούμενες εφαρμογές"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Επιτρέπει στην εφαρμογή την ανάκτηση λεπτομερών πληροφοριών σχετικά με τις τρέχουσες εκτελούμενες εργασίες και τις εργασίες που έχουν εκτελεστεί πρόσφατα. Τυχόν κακόβουλες εφαρμογές ενδέχεται να ανακαλύψουν ιδιωτικές πληροφορίες σχετικά με άλλες εφαρμογές."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"αναδιάταξη εκτελούμενων εφαρμογών"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Ήχος Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Τέλος"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Έξοδος μέσων"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Ενσωματωμένη οθόνη"</string>
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index eaa3578..4f7b087 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Allows the app to perform actions across different users on the device. Malicious apps may use this to violate the protection between users."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"full license to interact across users"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Allows all possible interactions across users."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"manage users"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Allows apps to manage users on the device, including query, creation and deletion."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"retrieve details of running apps"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Allows the app to retrieve detailed information about currently and recently running tasks. Malicious apps may discover private information about other apps."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"re-order running apps"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Done"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Media output"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Built-in Screen"</string>
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index b589afb..9108337 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite que la aplicación lleve a cabo acciones entre los diferentes usuarios del dispositivo. Las aplicaciones maliciosas pueden utilizar este permiso para infringir la protección entre usuarios."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"Licencia completa para interactuar con los usuarios"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Permite todas las interacciones posibles con los usuarios."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"Administrar usuarios"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Permite a las aplicaciones administrar a los usuarios del dispositivo, incluidas la creación y la eliminación de consultas."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"recuperar información sobre las aplicaciones en ejecución"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Permite que la aplicación recupere información detallada sobre tareas en ejecución y recientemente ejecutadas. Las aplicaciones malintencionadas pueden hallar información privada sobre otras aplicaciones."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"reorganizar aplicaciones en ejecución"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Listo"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index ec7bbb2..c998ff6 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite que la aplicación lleve a cabo acciones entre los diferentes usuarios del dispositivo. Las aplicaciones maliciosas pueden utilizar este permiso para infringir la protección entre usuarios."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licencia completa para interactuar con los usuarios"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Permite que la aplicación interactúe con los usuarios."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"administrar usuarios"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Permite a las aplicaciones administrar los usuarios del dispositivo, así como buscarlos, crearlos y eliminarlos."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"recuperar información de aplicaciones en ejecución"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Permite que la aplicación recupere información sobre tareas que se están ejecutando en este momento o que se han ejecutado recientemente. Las aplicaciones malintencionadas pueden usar este servicio para acceder a información privada sobre otras aplicaciones."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"reorganizar aplicaciones en ejecución"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fin"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Salida multimedia"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Pantalla integrada"</string>
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 957e941..872f485 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Lubab rakendusel teha toiminguid seadme erinevatel kasutajakontodel. Pahatahtlikud rakendused võivad kasutada seda kasutajatevahelise kaitse rikkumiseks."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"täielik litsents teha toiminguid erinevatel kasutajakontodel"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Lubab kõiki võimalikke toiminguid erinevatel kasutajakontodel."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"kasutajate haldamine"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Võimaldab rakendustel hallata seadme kasutajaid, sealhulgas päringuid, loomist ja kustutamist."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"töötavate rakenduste üksikasjade toomine"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Võimaldab rakendusel tuua üksikasjalikku teavet praegu töötavate ja hiljuti käitatud ülesannete kohta. Pahatahtlikud rakendused võivad tuvastada privaatset teavet muude rakenduste kohta."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"käitatud rakenduste ümberjärjestamine"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-heli"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Valmis"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Meediaväljund"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index d793c5d..ecdebe8 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -156,7 +156,7 @@
     <string name="global_action_power_off" msgid="4471879440839879722">"خاموش کردن"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"گزارش اشکال"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"گرفتن گزارش اشکال"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"این گزارش اطلاعات مربوط به وضعیت دستگاه کنونی شما را جمع‌آوری می‌کند تا به صورت یک پیام ایمیل ارسال شود. از زمان شروع گزارش اشکال تا آماده شدن برای ارسال اندکی زمان می‌برد؛ لطفاً صبور باشید."</string>
+    <string name="bugreport_message" msgid="398447048750350456">"این گزارش اطلاعات مربوط به وضعیت دستگاه کنونی شما را جمع‌آوری می‌کند تا به صورت یک پیام ایمیل ارسال شود. از زمان شروع گزارش اشکال تا آماده شدن برای ارسال اندکی زمان می‌برد؛ لطفاً شکیبا باشید."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"حالت ساکت"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"صدا خاموش است"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"صدا روشن است"</string>
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"به برنامه اجازه می‌دهد اقداماتی در بین کاربران مختلف در دستگاه انجام دهد. ممکن است برنامه‌های مخرب از این قابلیت برای نقض حفاظت موجود در بین کاربران استفاده کنند."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"مجوز کامل برای ارتباط بین کاربران"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"اجازه می‌دهد همه ارتباطات ممکن بین کاربران انجام شود."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"مدیریت کاربران"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"به برنامه‌ها اجازه می‌دهد مدیریت کاربران، از قبیل پرسش، ایجاد و حذف کاربران، را در دستگاه انجام دهند."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"بازیابی جزئیات برنامه‌های در حال اجرا"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"به برنامه اجازه می‎دهد تا اطلاعات مفصلی مربوط به کارهایی که در حال حاضر و اخیراً اجرا می‎شوند را بازیابی کند. برنامه‎های مخرب می‎توانند اطلاعات شخصی مربوط به برنامه‎های دیگر را پیدا کنند."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"تنظیم مجدد ترتیب برنامه‎های در حال اجرا"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"بلوتوث‌های صوتی"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"انجام شد"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"خروجی رسانه"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index e06dfcc..f6ab9f8 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Antaa sovelluksen suorittaa käyttäjien välisiä toimintoja laitteessa. Haitalliset sovellukset voivat vahingoittaa käyttäjien välistä suojausta."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"lupa suorittaa käyttäjien välisiä toimintoja"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Sallii kaikki käyttäjien väliset toiminnot."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"hallinnoi käyttäjiä"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Antaa sovelluksien hallinnoida laitteen käyttäjiä esim. hakemalla, luomalla tai poistamalla käyttäjiä."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"hae tiedot suoritettavista sovelluksista"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Antaa sovellukselle oikeuden noutaa käynnissä oleviin ja käynnissä olleisiin tehtäviin liittyviä tietoja. Haitalliset sovellukset saattavat saada näin muihin sovelluksiin liittyviä yksityisiä tietoja."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"käynnissä olevien sovellusten järjesteleminen"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ääni"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Valmis"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Median äänentoisto"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Sisäänrakennettu näyttö"</string>
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 7eab72d..c35fe8d 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -155,7 +155,7 @@
     <string name="global_action_lock" msgid="2844945191792119712">"Verrouillage de l\'écran"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Éteindre"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Rapport de bug"</string>
-    <string name="bugreport_title" msgid="2667494803742548533">"Établir un rapport de bug"</string>
+    <string name="bugreport_title" msgid="2667494803742548533">"Créer un rapport de bug"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme d\'e-mail. Merci de patienter pendant la préparation du rapport de bug. Cette opération peut prendre quelques instants."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mode silencieux"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Le son est désactivé."</string>
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permet à l\'application d\'effectuer des actions entre les différents utilisateurs de l\'appareil. Les applications malveillantes peuvent utiliser cette autorisation pour passer outre la protection entre les utilisateurs."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"autorisation totale d\'interagir entre les utilisateurs"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Permet toutes les interactions possibles entre les utilisateurs."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"Gérer les utilisateurs"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Permet aux applications de gérer les utilisateurs de l\'appareil, y compris la recherche, la création et la suppression d\'utilisateurs."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"récupérer les détails des applications en cours d\'exécution"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Permet à l\'application de récupérer des informations détaillées sur les tâches en cours d\'exécution ou récemment exécutées. Des applications malveillantes peuvent utiliser cette fonctionnalité pour obtenir des informations confidentielles relatives à d\'autres applications."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"réorganiser les applications en cours d\'exécution"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"OK"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Sortie multimédia"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 093c19d..6ea8f7b 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"एप्लिकेशन को उपकरण पर भिन्न उपयोगकर्ताओं के बीच कार्य निष्पादित करने देता है. दुर्भावनापूर्ण एप्लिकेशन उपयोगकर्ताओं के बीच सुरक्षा का उल्लंघन करने के लिए इसका उपयोग कर सकते हैं."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"उपयोगकर्ताओं के बीच सहभागिता करने के लिए पूर्ण लाइसेंस"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"उपयोगकर्ताओं के बीच सभी संभव सहभागिता करने देता है."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"उपयोगकर्ता प्रबंधित करें"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"एप्लिकेशन को उपकरण पर क्वेरी, निर्माण और हटाने सहित उपयोगकर्ताओं को प्रबंधित करने की सुविधा देता है."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"चल रहे एप्‍लिकेशन के विवरण प्राप्त करें"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"एप्लिकेशन को वर्तमान में और हाल ही में चल रहे कार्यों की जानकारी प्राप्त करने देता है. दुर्भावनापूर्ण एप्लिकेशन अन्य एप्लिकेशन के बारे में निजी जानकारी खोज सकते हैं."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"चल रहे एप्‍लिकेशन पुन: क्रमित करें"</string>
@@ -722,7 +724,7 @@
     <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"आपका सिम कार्ड स्‍थायी रूप से अक्षम कर दिया गया है."\n" दूसरे SIM कार्ड के लिए अपने वायरलेस सेवा प्रदाता से संपर्क करें."</string>
     <string name="lockscreen_transport_prev_description" msgid="201594905152746886">"पिछला ट्रैक बटन"</string>
     <string name="lockscreen_transport_next_description" msgid="6089297650481292363">"अगला ट्रैक बटन"</string>
-    <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"रोकें बटन"</string>
+    <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"पॉज़ करें बटन"</string>
     <string name="lockscreen_transport_play_description" msgid="5888422938351019426">"चलाएं बटन"</string>
     <string name="lockscreen_transport_stop_description" msgid="4562318378766987601">"रोकें बटन"</string>
     <string name="emergency_calls_only" msgid="6733978304386365407">"केवल आपातकालीन कॉल"</string>
@@ -1075,7 +1077,7 @@
     <string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"USB विशाल संग्रहण के लिए आपके USB संग्रहण का उपयोग करने में समस्‍या है."</string>
     <string name="usb_storage_error_message" product="default" msgid="2876018512716970313">"USB विशाल संग्रहण के लिए आपके SD कार्ड का उपयोग करने में समस्‍या है."</string>
     <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB कनेक्ट किया गया"</string>
-    <string name="usb_storage_notification_message" msgid="939822783828183763">"आपके कंप्‍यूटर में/से फ़ाइल की प्रतिलिपि बनाने के लिए चयन करें."</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>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ऑडियो"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"पूर्ण"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"मीडिया आउटपुट"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 2029530..26bc6ec 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Omogućuje aplikaciji izvršavanje radnji među korisnicima na uređaju. Zlonamjerne aplikacije mogu to iskoristiti za narušavanje zaštite među korisnicima."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"dozvola za potpunu interakciju među korisnicima"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Omogućuje sve moguće interakcije među korisnicima."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"upravljanje korisnicima"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Omogućuje aplikacijama upravljanje korisnicima na uređaju, uključujući upit, izradu i brisanje."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"dohvaćanje pojedinosti o pokrenutim aplikacijama"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Aplikaciji omogućuje dohvaćanje detaljnih informacija o trenutačno i nedavno pokrenutim zadacima. Zlonamjerne aplikacije mogu otkriti privatne informacije o drugim aplikacijama."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"promjena redoslijeda pokrenutih aplikacija"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth zvuk"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gotovo"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medijski izlaz"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 421c5be..42e7888 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Lehetővé teszi az alkalmazás számára, hogy több felhasználó között végezzen különféle műveleteket az eszközön. A rosszindulatú alkalmazások arra használhatják ezt, hogy megsértsék a felhasználók biztonságát."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"teljes licenc a felhasználók közötti interakcióhoz"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Lehetővé teszi az összes lehetséges interakciót a felhasználók között."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"Felhasználók kezelése"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Lehetővé teszi az alkalmazások számára a készüléken beállított felhasználók kezelését, beleértve a lekérdezéseket, a létrehozásokat és törléseket."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"futó alkalmazások részleteinek lekérése"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Lehetővé teszi az alkalmazás számára a jelenleg és a nemrég futó feladatok részletes adatainak lekérését. A rosszindulatú alkalmazások más alkalmazásokkal kapcsolatos privát adatokhoz férhetnek hozzá."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"futó alkalmazások átrendezése"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth hang"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Kész"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Médiakimenet"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 6699698..34e6a96 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -134,7 +134,7 @@
     <string name="me" msgid="6545696007631404292">"Saya"</string>
     <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opsi tablet"</string>
     <string name="power_dialog" product="default" msgid="1319919075463988638">"Opsi telepon"</string>
-    <string name="silent_mode" msgid="7167703389802618663">"Modus senyap"</string>
+    <string name="silent_mode" msgid="7167703389802618663">"Mode senyap"</string>
     <string name="turn_on_radio" msgid="3912793092339962371">"Hidupkan nirkabel"</string>
     <string name="turn_off_radio" msgid="8198784949987062346">"Matikan nirkabel"</string>
     <string name="screen_lock" msgid="799094655496098153">"Kunci layar"</string>
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Mengizinkan aplikasi melakukan tindakan antar-pengguna yang berbeda pada perangkat. Aplikasi berbahaya dapat menggunakan ini untuk mengganggu perlindungan antar-pengguna."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"lisensi penuh untuk berinteraksi antar-pengguna"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Mengizinkan semua interaksi yang mungkin antar-pengguna."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"kelola pengguna"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Memungkinkan aplikasi mengelola pengguna pada perangkat, termasuk kueri, pembuatan, dan penghapusan."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"mengambil detail aplikasi yang sedang berjalan"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Izinkan aplikasi mengambil informasi mendetail tentang tugas yang saat ini dan baru-baru ini dijalankan. Aplikasi berbahaya dapat menemukan informasi pribadi tentang aplikasi lain."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"menyusun ulang apl yang berjalan"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Keluaran media"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Layar Ada Di Dalamnya"</string>
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 5f64c20..a693dc8 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Consente all\'applicazione di compiere azioni per diversi utenti sul dispositivo. Le applicazioni dannose potrebbero farne uso per violare la protezione tra utenti."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licenza completa per l\'interazione tra utenti"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Consente tutte le interazioni possibili tra gli utenti."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"Gestione utenti"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Consente alle applicazioni di gestire gli utenti sul dispositivo, nonché query, creazione ed eliminazione."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"recupero dettagli applicazioni in esecuzione"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Consente all\'applicazione di recuperare informazioni dettagliate sulle attività attualmente e recentemente in esecuzione. Le applicazioni dannose potrebbero scoprire informazioni riservate su altre applicazioni."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"riordinamento applicazioni in esecuzione"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fine"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Uscita media"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Schermo incorporato"</string>
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 5432f26..a318907 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"מאפשר ליישום לבצע פעולות בין משתמשים שונים במכשיר. יישומים זדוניים עשויים להשתמש ביכולת זו כדי לפרוץ את ההגנה בין משתמשים."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"רישיון מלא לבצע אינטראקציה בין משתמשים"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"מאפשר את כל האינטראקציות האפשריות בין משתמשים."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"נהל משתמשים"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"מאפשר ליישומים לנהל משתמשים במכשיר, כולל שאילתה, יצירה ומחיקה."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"אחזור פרטי יישומים פועלים"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"מאפשר ליישום לאחזר מידע מפורט על המשימות הנוכחיות הפועלות ועל משימות שפעלו לאחרונה. יישומים זדוניים עלולים לגלות מידע אישי על יישומים אחרים."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"סידור מחדש של יישומים פעילים"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"אודיו Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"סיום"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"פלט מדיה"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"מסך מובנה"</string>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index f8ab2bf..dc0c139 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"端末上の各ユーザーに対して操作を実行することをアプリに許可します。この許可を悪意のあるアプリに利用されると、ユーザー間の保護が侵害される恐れがあります。"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ユーザー間で交流するための完全ライセンス"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"ユーザー間の交流をすべて許可します。"</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"ユーザーの管理"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"ユーザーの問い合わせ、作成、削除を含め、端末上のユーザーを管理することをアプリに許可します。"</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"実行中のアプリの詳細の取得"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"現在実行中のタスクまたは最近実行したタスクに関する情報の取得をアプリに許可します。この許可を悪意のあるアプリに利用されると、他のアプリに関する非公開情報が読み取られる恐れがあります。"</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"実行中のアプリの順序変更"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth音声"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完了"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"メディア出力"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index ec301a4..f6ae2af 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"앱이 기기에서 다양한 사용자에 대한 작업을 수행할 수 있도록 허용합니다. 이 경우 악성 앱이 사용자 간의 보호를 위반할 수 있습니다."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"여러 사용자와의 상호작용을 위한 정식 라이센스"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"여러 사용자와의 가능한 모든 상호작용을 허용합니다."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"사용자 관리"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"앱이 기기에서 검색, 생성 및 삭제를 포함한 사용자 관리를 할 수 있도록 허용합니다."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"실행 중인 앱 세부정보 검색"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"앱이 현재 실행 중이거나 최근에 실행된 작업에 대한 상세한 정보를 검색할 수 있도록 허용합니다. 이 경우 악성 앱이 다른 앱에 대한 개인 정보를 검색할 수 있습니다."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"실행 중인 앱 순서 재지정"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"블루투스 오디오"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"완료"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"미디어 출력"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 7f44e81..7692620 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Leidžiama programai atlikti veiksmus skirtingų įrenginio naudotojų profiliuose. Kenkėjiškos programos gali pasinaudoti šiuo leidimu, kad pažeistų naudotojų saugumą."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"visa licencija, leidžianti sąveikauti su naudotojais"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Leidžiama bet kokia sąveika tarp naudotojų."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"tvarkyti naudotojus"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Leidžia tvarkyti įrenginio naudotojų duomenis, įskaitant užklausų teikimą, duomenų kūrimą ir ištrynimą."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"nuskaityti veikiančių programų išsamią informaciją"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Leidžiama programai nuskaityti išsamią informaciją apie šiuo ir pastaruoju metu vykdomas užduotis. Kenkėjiškos programos gali surasti privačios informacijos apie kitas programas."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"pertvarkyti vykdomas programas"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"„Bluetooth“ garsas"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Atlikta"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medijos išvestis"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 1d46ccb..d63c45b 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Ļauj lietotnei veikt darbības vairāku ierīces lietotāju kontos. Ļaunprātīgas lietotnes var izmantot šo atļauju, lai apdraudētu lietotāju kontu drošību."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"pilna licence ar atļauju darboties visos lietotāju kontos"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Ļauj veikt jebkādas darbības visos lietotāju kontos."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"Lietotāju pārvaldība"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Ļauj lietotnēm pārvaldīt ierīces lietotājus, tostarp izveidot un dzēst lietotājus vai veidot vaicājumus."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"Informācijas izguve par izmantotajām lietotnēm"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Ļauj lietotnei izgūt informāciju par šobrīd un nesen veiktajiem uzdevumiem. Ļaunprātīgas lietotnes var atklāt privātu informāciju par citām lietotnēm."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"pārkārtot izmantotās lietotnes"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gatavs"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Multivides izeja"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index c8a08de..a22ff51 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -154,12 +154,9 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Pilihan telefon"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Kunci skrin"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Matikan kuasa"</string>
-    <!-- no translation found for global_action_bug_report (7934010578922304799) -->
-    <skip />
-    <!-- no translation found for bugreport_title (2667494803742548533) -->
-    <skip />
-    <!-- no translation found for bugreport_message (398447048750350456) -->
-    <skip />
+    <string name="global_action_bug_report" msgid="7934010578922304799">"Laporan pepijat"</string>
+    <string name="bugreport_title" msgid="2667494803742548533">"Ambil laporan pepijat"</string>
+    <string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpul maklumat tentang keadaan peranti semasa anda untuk dihantarkan sebagai mesej e-mel. Proses ini akan mengambil sedikit masa bermula dari laporan pepijat sehingga siap untuk dihantar; jadi diharap bersabar."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mod senyap"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Bunyi DIMATIKAN"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Bunyi DIHIDUPKAN"</string>
@@ -227,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Membenarkan apl melakukan tindakan merentasi pengguna berbeza pada peranti. Apl hasad boleh menggunakan ini untuk melanggar perlindungan antara pengguna."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"lesen penuh untuk berinteraksi sesama pengguna"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Membenarkan semua interaksi yang mungkin sesama pengguna."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"urus pengguna"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Membenarkan apl mengurus pengguna pada peranti ini, termasuk pertanyaan, pembuatan dan pemadaman."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"dapatkan butiran apl yang berjalan"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Membenarkan apl untuk mendapatkan maklumat terperinci tentang tugasan yang sedang dan baru berjalan. Apl hasad boleh mendapat maklumat peribadi tentang apl lain."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"susun semula tertib apl yang dijalankan"</string>
@@ -1312,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Selesai"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Output media"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 68f8918..3a4212b 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Tillater at appen utfører handlinger på tvers av ulike brukere på enheten. Skadelige apper kan utnytte dette til å bryte beskyttelsen mellom brukere."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"full lisens til å samhandle på tvers av brukere"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Tillater alle mulige samhandlinger på tvers av brukere."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"Administrere brukere"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Lar apper administrere brukere på enheten, herunder forespørsler, oppretting og sletting."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"hente informasjon om apper som kjører"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Tillater at appen henter ut informasjon om oppgaver som kjører eller nylig har kjørt. Skadelige apper kan bruke dette til å oppdage privat informasjon om andre apper."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"Endre rekkefølge på apper som kjører"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-lyd"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Fullført"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieutgang"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Innebygd skjerm"</string>
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 985da7e9..89e52a9 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Hiermee kan de app acties uitvoeren voor verschillende gebruikers van het apparaat. Schadelijke apps kunnen dit gebruiken om de beveiliging tussen gebruikers te schenden."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"volledige toestemming voor interactie tussen gebruikers"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Hiermee is alle mogelijke interactie tussen gebruikers toegestaan."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"gebruikers beheren"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Toestaan dat apps gebruikers op het apparaat beheren, inclusief het opvragen van gegevens en het maken en verwijderen van gebruikers."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"details van actieve apps ophalen"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Hiermee kan de app gedetailleerde informatie over huidige en recent uitgevoerde taken ophalen. Schadelijke apps kunnen op deze manier mogelijk privé-informatie over andere apps achterhalen."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"actieve apps opnieuw rangschikken"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gereed"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Media-uitvoer"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Ingebouwd scherm"</string>
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 19f317d..e16d308 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Umożliwia aplikacji wykonywanie działań dotyczących różnych użytkowników urządzenia. Złośliwe aplikacje mogą to wykorzystać do złamania zabezpieczeń na kontach użytkowników."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"pełna licencja na interakcje między użytkownikami"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Zezwala na wszystkie możliwe interakcje między użytkownikami."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"zarządzanie użytkownikami"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Pozwala aplikacjom na zarządzanie użytkownikami na urządzeniu, w tym na ich sprawdzanie, tworzenie i usuwanie."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"Pobieraj informacje o uruchomionych aplikacjach"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Zezwala aplikacji na pobieranie informacji o obecnie i ostatnio uruchomionych zadaniach. Złośliwe aplikacje mogą uzyskać dostęp do prywatnych informacji na temat innych aplikacji."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"zmienianie kolejności uruchomionych aplikacji"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Dźwięk Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Gotowe"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Wyjście multimediów"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 788d1a2..996be49 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite que a aplicação execute ações com diferentes utilizadores no dispositivo. Aplicações maliciosas poderão utilizar esta opção para violar a proteção entre utilizadores."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licença completa para interagir entre utilizadores"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Permite todas as interações possíveis entre utilizadores."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"gerir utilizadores"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Permite às aplicações a gestão de utilizadores no dispositivo, incluindo a criação e eliminação de consultas."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"obter detalhes das aplicações em execução"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Permite à aplicação obter informações detalhadas sobre tarefas atualmente em execução e recentemente executadas. As aplicações maliciosas poderão descobrir informações privadas de outras aplicações."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"reordenar as aplicações em execução"</string>
@@ -1132,7 +1134,7 @@
     <string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"O armazenamento USB foi removido. Insira um novo suporte de dados."</string>
     <string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"Cartão SD removido. Insira um novo cartão."</string>
     <string name="activity_list_empty" msgid="1675388330786841066">"Não foi encontrada nenhuma atividade correspondente."</string>
-    <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"actualizar estatísticas de utilização de componentes"</string>
+    <string name="permlab_pkgUsageStats" msgid="8787352074326748892">"atualizar estatísticas de utilização de componentes"</string>
     <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"Permite que a aplicação modifique as estatísticas de utilização de componentes recolhidas. Não se destina a utilização por aplicações normais."</string>
     <string name="permlab_copyProtectedData" msgid="4341036311211406692">"copiar conteúdo"</string>
     <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Permite à aplicação invocar o serviço de contentor predefinido para copiar conteúdo. Não se destina a ser utilizado por aplicações normais."</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Concluído"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de som multimédia"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index c3524db..7d7672f 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -154,12 +154,9 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Opções do telefone"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Bloquear tela"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
-    <!-- no translation found for global_action_bug_report (7934010578922304799) -->
-    <skip />
-    <!-- no translation found for bugreport_title (2667494803742548533) -->
-    <skip />
-    <!-- no translation found for bugreport_message (398447048750350456) -->
-    <skip />
+    <string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de bugs"</string>
+    <string name="bugreport_title" msgid="2667494803742548533">"Obter relatório de bugs"</string>
+    <string name="bugreport_message" msgid="398447048750350456">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
     <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>
@@ -227,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite que o aplicativo execute ações entre os diversos usuários do aparelho. Aplicativos mal-intencionados podem usar isto para violar a proteção entre os usuários."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"permissão total para interagir entre os usuários"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Permite todas as interações possíveis entre os usuários."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"gerenciar usuários"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Permite que os aplicativos gerenciem os usuários do dispositivo, incluindo a consulta, a criação e a exclusão de usuários."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"recuperar detalhes dos aplicativos em execução"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Permite que o aplicativo recupere informações detalhadas sobre tarefas executadas atual e recentemente. Aplicativos maliciosos podem descobrir informações privadas sobre outros aplicativos."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"reordenar os aplicativos em execução"</string>
@@ -1312,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Áudio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Concluído"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Saída de mídia"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 097d6de..a093bfb 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -303,6 +303,10 @@
     <skip />
     <!-- no translation found for permdesc_interactAcrossUsersFull (376841368395502366) -->
     <skip />
+    <!-- no translation found for permlab_manageUsers (1676150911672282428) -->
+    <skip />
+    <!-- no translation found for permdesc_manageUsers (8409306667645355638) -->
+    <skip />
     <!-- no translation found for permlab_getDetailedTasks (6229468674753529501) -->
     <skip />
     <!-- no translation found for permdesc_getDetailedTasks (153824741440717599) -->
@@ -2066,4 +2070,6 @@
     <skip />
     <!-- no translation found for media_route_button_content_description (5758553567065145276) -->
     <skip />
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 1deae16..6300a1f4 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -156,7 +156,7 @@
     <string name="global_action_power_off" msgid="4471879440839879722">"Opriţi alimentarea"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Raport despre erori"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"Executaţi un raport despre erori"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"Acest raport va colecta informaţii despre starea actuală a dispozitivului, pentru a le trimite ca mesaj de e-mail. Va dura un timp din momentul pornirii raportului despre erori şi până când acesta va fi gata pentru a fi trimis, prin urmare vă rugăm să aveţi puţină răbdare."</string>
+    <string name="bugreport_message" msgid="398447048750350456">"Acest raport va colecta informaţii despre starea actuală a dispozitivului, pentru a le trimite într-un e-mail. Aveți răbdare după pornirea raportului despre erori până când va fi gata de trimis."</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mod Silenţios"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Sunetul este DEZACTIVAT"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Sunetul este ACTIVAT"</string>
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Permite aplicaţiei să efectueze acţiuni pentru diferiţi utilizatori pe dispozitiv. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a încălca protecţia între utilizatori."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"licenţă completă pentru interacţiune între utilizatori"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Permite toate interacţiunile posibile între utilizatori."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"gestionează utilizatorii"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Permite aplicaţiilor să gestioneze utilizatorii de pe dispozitiv, inclusiv interogarea, crearea şi ştergerea acestora."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"preia detalii despre aplicaţiile care rulează"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Permite aplicaţiei să preia informaţii detaliate despre activităţile rulate curent şi recent. Aplicaţiile rău intenţionate pot să descopere informaţii private despre alte aplicaţii."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"reordonare aplicaţii care rulează"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Terminat"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Rezultate media"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index c32f93a..004b2b6 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Приложение сможет выполнять действия во всех аккаунтах на этом устройстве. При этом защита от вредоносных приложений может быть недостаточной."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"разрешить полное взаимодействие со всеми аккаунтами"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Приложение сможет выполнять любые действия во всех аккаунтах на этом устройстве."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"Управлять аккаунтами"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Приложения смогут управлять аккаунтами на этом устройстве (выполнять поиск, создавать и удалять их)"</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"получение сведений о работающих приложениях"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Приложение сможет получать подробные сведения о недавно запущенных и выполняемых задачах. При этом конфиденциальная информация о других приложениях не будет защищена от вредоносных программ."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"Упорядочивание запущенных приложений"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Воспроизведение звука через Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Перенаправлять поток мультимедиа"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 3464faa..15c359c 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Umožňuje aplikácii vykonávať akcie naprieč rôznymi používateľmi zariadenia. Škodlivé aplikácie môžu toto povolenie zneužiť na obídenie ochrany medzi používateľmi."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"plná licencia na interakcie naprieč používateľmi"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Umožňuje všetky možné interakcie naprieč používateľmi."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"správa používateľov"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Umožňuje aplikáciám spravovať používateľov v zariadení, vrátane vyhľadávania dopytov, vytvorenia a odstránenia."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"načítať podrobnosti o spustených aplikáciách"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Umožňuje aplikácii načítať podrobné informácie o aktuálnych a nedávno spustených úlohách. Škodlivé aplikácie môžu odhaliť súkromné informácie o iných aplikáciách."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"zmeniť poradie spustených aplikácií"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Hotovo"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Výstup médií"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 35246b1..1ede6b7 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Aplikaciji omogoča izvajanje dejanj za različne uporabnike v napravi. Zlonamerne aplikacije lahko to uporabijo za kršitev zaščite med uporabniki."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"polna licenca za interakcijo z uporabniki"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Dovoli vso mogočo interakcijo z uporabniki"</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"upravljanje uporabnikov"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Aplikacijam omogoča upravljanje uporabnikov v napravi, vključno z iskanjem, ustvarjanjem in brisanjem."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"prejemanje podrobnosti o aplikacijah, ki se izvajajo"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Aplikaciji omogoča, da dobi podatke o trenutnih in nedavno izvajajočih se opravilih. Zlonamerne aplikacije lahko odkrijejo zasebne podatke o drugih aplikacijah."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"preurejanje programov, ki se izvajajo"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Zvok prek Bluetootha"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Končano"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Izhod predstavnosti"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Vgrajen zaslon"</string>
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index d5c0561..e4cf347 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Дозвољава апликацији да обавља радње између различитих корисника на уређају. Злонамерне апликације могу да користе ово да би угрозиле заштиту између корисника."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"пуна лиценца за интеракцију између корисника"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Дозвољава све могуће интеракције између корисника."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"управљање корисницима"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Дозвољава апликацијама да управљају корисницима на уређају, укључујући постављање упита, прављење и брисање."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"преузимање детаља о покренутим апликацијама"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Дозвољава апликацији да преузима детаљне информације о актуелним и недавно покренутим задацима. Злонамерне апликације могу да открију приватне информације о другим апликацијама."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"промена редоследа покренутих апликација"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth аудио"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Излаз медија"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 89c0796d..493a0bb 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Tillåter att appen utför åtgärder mellan användare på enheten. Skadliga appar kan använda detta som ett sätt att kringgå skyddet mellan användare."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"fullständig behörighet att interagera mellan användare"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Tillåter all slags interaktion mellan användare."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"hantera användare"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Tillåter att appen hanterar användare på enheten, inklusive att söka efter, skapa och radera användarinformation."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"hämta information om aktiva appar"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Tillåter att appen hämtar detaljerad information om uppgifter som körs och har körts. Skadliga appar kan upptäcka personliga uppgifter om andra appar."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"byt ordning på appar som körs"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth-ljud"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Klar"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medieuppspelning"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Inbyggd skärm"</string>
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 3fd7af05..759000d 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Inaruhusu programu kutenda vitendo kwa watumiaji tofauti kwenye kifaa. Programu hasidi huenda zikatumia hii ili kukiuka ulinzi kati ya watumiaji."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"leseni kamili ili kutagusana na watumiaji"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Inaruhusu miingialiano yote inayowezekana kwa watumiaji."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"dhibiti watumiaji"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Inaruhusu programu kudhibiti watumiaji kwenye kifaa, pamoja na hoji, uundaji na ufutaji."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"epua maelezo ya programu zinazoendeshwa"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Huruhusu programu kuepua maelezo tondoti kuhusu kazi za sasa na zinazoendelea hivi karibuni. Programu hasidi huenda zikagundua maelezo ya kibinafsi kuhusu programu zingine."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"Agiza tena programu za kuendeshwa"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Sauti ya Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Kwisha"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Towe la midia"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Skrini Iliyojengewa ndani"</string>
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 61e25b2..c25e6db 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"อนุญาตให้แอปพลิเคชันทำงานได้กับผู้ใช้หลายรายบนอุปกรณ์นี้ แอปพลิเคชันที่เป็นอันตรายอาจใช้การทำงานนี้ในการบุกรุกการป้องกันระหว่างผู้ใช้"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ใบอนุญาตฉบับเต็มสำหรับการโต้ตอบระหว่างผู้ใช้"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"อนุญาตให้ทำการโต้ตอบทุกชนิดที่เป็นไปได้กับผู้ใช้ต่างๆ"</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"จัดการผู้ใช้"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"อนุญาตให้แอปพลิเคชันจัดการผู้ใช้บนอุปกรณ์ รวมทั้งการถามคำถาม การสร้าง และการลบ"</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"ดึงรายละเอียดของแอปที่ทำงานอยู่"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"อนุญาตให้แอปพลิเคชันดึงข้อมูลเกี่ยวกับงานที่กำลังเรียกใช้อยู่ในปัจจุบันและงานล่าสุด แอปพลิเคชันที่เป็นอันตรายอาจค้นพบข้อมูลเฉพาะตัวเกี่ยวกับแอปพลิเคชันอื่นๆ"</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"จัดลำดับแอปพลิเคชันที่ทำงานอยู่ใหม่"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"เสียงบลูทูธ"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"เสร็จสิ้น"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"เอาต์พุตสื่อ"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index adf7ef2..ab4ff29 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Binibigyang-daan ang app upang magsagawa ng mga pagkilos sa kabuuan ng iba\'t ibang mga user sa device. Maaari itong gamitin ng nakakahamak na apps upang lumabag sa proteksyon sa pagitan ng mga user."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ganap na lisensya upang makipag-ugnayan sa kabuuan ng mga user"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Pinapayagan ang lahat ng posibleng pakikipag-ugnayan sa kabuuan ng mga user."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"pamahalaan ang mga user"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Binibigyang-daan ang apps na mamahala ng mga user sa device, kabilang ang query, paglikha at pagtanggal."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"bawiin ang mga detalye ng gumaganang apps"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Binibigyang-daan ang app na bawiin ang detalyadong impormasyon tungkol sa mga kasalukuyan at kamakailang gumaganang gawain. Maaaring makatuklas ang nakakahamak na apps ng pribadong impormasyon tungkol sa iba pang apps."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"muling isaayos ang tumatakbong apps"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Audio sa Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tapos na"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Output ng media"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index e15402a..95637dc 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Uygulamaya cihazdaki farklı kullanıcılar arasında işlem gerçekleştirme izni verir. Kötü amaçlı uygulamalar bu izinle kullanıcılar arasındaki korumayı ihlal edebilir."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"kullanıcılar arasında etkileşim kurmak için tam izin"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Kullanıcılar arasında tüm etkileşime izin verir."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"kullanıcıları yönet"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Uygulamalara, sorgulama, oluşturma ve silme işlemleri de dahil olmak üzere cihazdaki kullanıcıları yönetme izni verir."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"çalışan uygulamaların ayrıntılarını al"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Uygulamaya, şu anda çalışmakta olan ve son çalışan işlemler hakkında ayrıntılı bilgi alma izni verir. Kötü amaçlı uygulamalar diğer uygulamalar hakkında gizli bilgileri ele geçirebilir."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"çalışan uygulamaları yeniden sırala"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth ses"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Tamamlandı"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Medya çıkışı"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index d37cbd8..a8633e8 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Дозволяє програмі виконувати дії щодо різних користувачів на пристрої. Шкідливі програми можуть використовувати це для порушення захисту окремих користувачів."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"повна ліцензія на взаємодію між користувачами"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Дозволяє всі можливі взаємодії щодо користувачів."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"керувати користувачами"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Дозволяє програмам керувати користувачами на пристрої, зокрема надсилати запити про користувачів, створювати й видаляти їх."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"отримувати дані про запущені програми"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Дозволяє програмі отримувати інформацію про поточні й останні запущені завдання. Шкідливі програми можуть виявляти особисту інформацію про інші програми."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"змінювати порядок запущених програм"</string>
@@ -1309,4 +1311,5 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Аудіо Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Готово"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Вивід медіа-даних"</string>
+    <string name="display_manager_built_in_display" msgid="9042666544146043569">"Вбудований екран"</string>
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 2653005..384a1ee 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -220,10 +220,12 @@
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Cho phép ứng dụng nhận và xử lý tin nhắn WAP. Quyền này bao gồm khả năng giám sát hoặc xóa tin nhắn được gửi cho bạn mà không hiển thị chúng cho bạn."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"truy xuất các ứng dụng đang chạy"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Cho phép ứng dụng truy xuất thông tin về các công việc đã và đang chạy gần đây. Việc này có thể cho phép ứng dụng phát hiện thông tin về những ứng dụng nào đã được sử dụng trên thiết bị."</string>
-    <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"tương tác với người dùng"</string>
-    <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Cho phép ứng dụng thực hiện hành động với những người dùng khác trên thiết bị. Ứng dụng độc hại có thể sử dụng quyền này để vi phạm khả năng bảo vệ giữa người dùng."</string>
-    <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"cấp phép đầy đủ để tương tác với người dùng"</string>
-    <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Cho phép tất cả các tương tác có thể xảy ra với người dùng."</string>
+    <string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"tương tác giữa người dùng"</string>
+    <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Cho phép ứng dụng thực hiện hành động giữa những người dùng khác trên thiết bị. Ứng dụng độc hại có thể sử dụng quyền này để vi phạm khả năng bảo vệ giữa người dùng."</string>
+    <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"cấp phép đầy đủ để tương tác giữa người dùng"</string>
+    <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Cho phép tất cả các tương tác giữa người dùng."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"quản lý người dùng"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Cho phép ứng dụng quản lý người dùng trên thiết bị, bao gồm truy vấn, tạo và xóa."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"truy xuất chi tiết về các ứng dụng đang chạy"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Cho phép ứng dụng truy xuất thông tin chi tiết về các tác vụ đã và đang chạy gần đây. Ứng dụng độc hại có thể phát hiện thông tin riêng tư về các ứng dụng khác."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"sắp xếp lại những ứng dụng đang chạy"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Âm thanh Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Xong"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Đầu ra phương tiện"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 7f6955d..289dcf8 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -154,12 +154,9 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"手机选项"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"屏幕锁定"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"关机"</string>
-    <!-- no translation found for global_action_bug_report (7934010578922304799) -->
-    <skip />
-    <!-- no translation found for bugreport_title (2667494803742548533) -->
-    <skip />
-    <!-- no translation found for bugreport_message (398447048750350456) -->
-    <skip />
+    <string name="global_action_bug_report" msgid="7934010578922304799">"错误报告"</string>
+    <string name="bugreport_title" msgid="2667494803742548533">"提交错误报告"</string>
+    <string name="bugreport_message" msgid="398447048750350456">"这会收集有关当前设备状态的信息,并以电子邮件的形式进行发送。从开始生成错误报告到准备好发送需要一点时间,请耐心等待。"</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"静音模式"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"声音已关闭"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"声音已开启"</string>
@@ -227,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"允许该应用在设备上跨多个用户执行操作。恶意应用可能会借此破坏用户之间的保护措施。"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"完全允许在用户之间进行互动"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"允许在用户之间进行所有可能的互动。"</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"管理用户"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"允许应用管理设备上的用户(包括查询、创建和删除用户)。"</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"检索正在运行的应用的详细信息"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"允许该应用检索当前正在运行和近期运行的任务的详细信息。恶意应用可能会发现有关其他应用的私密信息。"</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"对正在运行的应用重新排序"</string>
@@ -1071,13 +1070,13 @@
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff900000">"新增:"</font></string>
     <string name="perms_description_app" msgid="5139836143293299417">"由“<xliff:g id="APP_NAME">%1$s</xliff:g>”提供。"</string>
     <string name="usb_storage_activity_title" msgid="4465055157209648641">"USB 大容量存储设备"</string>
-    <string name="usb_storage_title" msgid="5901459041398751495">"USB 已连接"</string>
+    <string name="usb_storage_title" msgid="5901459041398751495">"已连接 USB"</string>
     <string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"您已通过 USB 连接至计算机。如果您要在计算机与 Android 设备的 USB 存储设备之间复制文件,请触摸下面的按钮。"</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="default" msgid="2876018512716970313">"使用 SD 卡作为 USB 大容量存储设备时出现问题。"</string>
-    <string name="usb_storage_notification_title" msgid="8175892554757216525">"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>
@@ -1312,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"蓝牙音频"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"媒体输出线路"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 36dcf29..96ba8c1 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -156,7 +156,7 @@
     <string name="global_action_power_off" msgid="4471879440839879722">"關機"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"錯誤報告"</string>
     <string name="bugreport_title" msgid="2667494803742548533">"取得錯誤報告"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"這會收集您目前裝置狀態的相關資訊,以便透過電子郵件傳送。從開始建立錯誤報告到準備傳送,這段過程可能需要一點時間,敬請耐心等候。"</string>
+    <string name="bugreport_message" msgid="398447048750350456">"這會收集您目前裝置狀態的相關資訊,以便透過電子郵件傳送。從錯誤報告開始建立到準備傳送的這段過程可能需要一點時間,敬請耐心等候。"</string>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"靜音模式"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"音效已關閉"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"音效已開啟"</string>
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"允許應用程式對裝置上的所有使用者執行各種動作。請注意,惡意應用程式可能利用此功能侵害使用者之間的保護機制。"</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"完整授權對所有使用者執行各種動作"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"允許對所有使用者執行各種可能的動作。"</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"管理使用者"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"允許應用程式管理裝置上的使用者,包括查詢、建立及刪除使用者。"</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"擷取執行中應用程式的詳細資訊"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"允許應用程式擷取目前及最近所執行任務的詳細資訊。請注意,惡意應用程式可能會找出其他應用程式的不公開資訊。"</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"重新排序正在執行的應用程式"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"藍牙音訊"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"完成"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"媒體輸出"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 8978e52..2a17f8f 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -224,6 +224,8 @@
     <string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"Ivumela uhlelo lokusebenza ukwenza izenzo kubasebenzisi bonke kudivayisi. Izinhlelo zokusebenza ezingalungile zingasebenzisa lokhu ukwephula ukuvikela phakathi kwabasebenzisi."</string>
     <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"ilayisensi egcwele yokuhlanganyela kubasebenzisi"</string>
     <string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"Ivumela konke ukuhlanganyela phakathi kwabasebenzisi."</string>
+    <string name="permlab_manageUsers" msgid="1676150911672282428">"phatha abasebenzisi"</string>
+    <string name="permdesc_manageUsers" msgid="8409306667645355638">"Ivumela izinhlelo zokusebenza ukuphatha abasebenzisi kudivayisi, kufaka phakathi umbuzo, ukudala nokususa."</string>
     <string name="permlab_getDetailedTasks" msgid="6229468674753529501">"thola kabusha imininingwane yezinhlelo zokusebenza ezisebenzayo"</string>
     <string name="permdesc_getDetailedTasks" msgid="153824741440717599">"Ivumela uhlelo lokusebenza ukuthola kabusha ulwazi mayelana nezinto ezenzeka manje nezisanda kwenzeka. Izinhlelo zokusebenza ezingalungile zingathola imininingwane eyimfihlo mayelana nezinye izinhlelo zokusebenza."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"misa kabusha izinsiza ezisebenzayo"</string>
@@ -1309,4 +1311,6 @@
     <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Umsindo we-Bluetooth"</string>
     <string name="media_route_chooser_grouping_done" msgid="7966438307723317169">"Qedile"</string>
     <string name="media_route_button_content_description" msgid="5758553567065145276">"Okukhiphayo kwemidiya"</string>
+    <!-- no translation found for display_manager_built_in_display (9042666544146043569) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ee0ff8e..86d03ad 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -533,25 +533,48 @@
     <integer name="config_longPressOnHomeBehavior">2</integer>
 
     <!-- Array of light sensor LUX values to define our levels for auto backlight brightness support.
-         The N entries of this array define N + 1 zones as follows:
+         The N entries of this array define N + 1 control points as follows:
 
-         Zone 0:        0 <= LUX < array[0]
-         Zone 1:        array[0] <= LUX < array[1]
+         Point 1:        LUX <= 0 (implicit)
+         Point 2:        0 < level[1] == LUX < level[2]
          ...
-         Zone N:        array[N - 1] <= LUX < array[N]
-         Zone N + 1:    array[N] <= LUX < infinity
+         Point N:        level[N - 1] == LUX < level[N]
+         Point N + 1:    level[N] <= LUX < infinity
+
+         The control points must be strictly increasing.  Each control point
+         corresponds to an entry in the brightness backlight values arrays.
+         For example, if LUX == level[1] (first element of the levels array)
+         then the brightness will be determined by value[1] (first element
+         of the brightness values array).
+
+         Spline interpolation is used to determine the auto-brightness
+         backlight values for LUX levels between these control points.
 
          Must be overridden in platform specific overlays -->
     <integer-array name="config_autoBrightnessLevels">
     </integer-array>
 
+    <!-- Minimum screen brightness setting allowed by the power manager.
+         The user is forbidden from setting the brightness below this level. -->
+    <integer name="config_screenBrightnessSettingMinimum">10</integer>
 
-    <!-- Minimum screen brightness allowed by the power manager. -->
-    <integer name="config_screenBrightnessDim">20</integer>
+    <!-- Maximum screen brightness allowed by the power manager.
+         The user is forbidden from setting the brightness above this level. -->
+    <integer name="config_screenBrightnessSettingMaximum">255</integer>
+
+    <!-- Default screen brightness setting.
+         Must be in the range specified by minimum and maximum. -->
+    <integer name="config_screenBrightnessSettingDefault">102</integer>
+
+    <!-- Screen brightness used to dim the screen when the user activity
+         timeout expires.  May be less than the minimum allowed brightness setting
+         that can be set by the user. -->
+    <integer name="config_screenBrightnessDim">10</integer>
 
     <!-- Array of output values for LCD backlight corresponding to the LUX values
          in the config_autoBrightnessLevels array.  This array should have size one greater
          than the size of the config_autoBrightnessLevels array.
+         The brightness values must be between 0 and 255 and be non-decreasing.
          This must be overridden in platform specific overlays -->
     <integer-array name="config_autoBrightnessLcdBacklightValues">
     </integer-array>
@@ -559,6 +582,7 @@
     <!-- Array of output values for button backlight corresponding to the LUX values
          in the config_autoBrightnessLevels array.  This array should have size one greater
          than the size of the config_autoBrightnessLevels array.
+         The brightness values must be between 0 and 255 and be non-decreasing.
          This must be overridden in platform specific overlays -->
     <integer-array name="config_autoBrightnessButtonBacklightValues">
     </integer-array>
@@ -566,6 +590,7 @@
     <!-- Array of output values for keyboard backlight corresponding to the LUX values
          in the config_autoBrightnessLevels array.  This array should have size one greater
          than the size of the config_autoBrightnessLevels array.
+         The brightness values must be between 0 and 255 and be non-decreasing.
          This must be overridden in platform specific overlays -->
     <integer-array name="config_autoBrightnessKeyboardBacklightValues">
     </integer-array>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 38a431f..e17a05d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -479,6 +479,7 @@
   <java-symbol type="string" name="decline" />
   <java-symbol type="string" name="default_text_encoding" />
   <java-symbol type="string" name="description_target_unlock_tablet" />
+  <java-symbol type="string" name="display_manager_built_in_display" />
   <java-symbol type="string" name="double_tap_toast" />
   <java-symbol type="string" name="elapsed_time_short_format_h_mm_ss" />
   <java-symbol type="string" name="elapsed_time_short_format_mm_ss" />
@@ -1470,6 +1471,9 @@
   <java-symbol type="integer" name="config_notificationsBatteryLowARGB" />
   <java-symbol type="integer" name="config_notificationsBatteryMediumARGB" />
   <java-symbol type="integer" name="config_radioScanningTimeout" />
+  <java-symbol type="integer" name="config_screenBrightnessSettingMinimum" />
+  <java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
+  <java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
   <java-symbol type="integer" name="config_screenBrightnessDim" />
   <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
   <java-symbol type="layout" name="am_compat_mode_dialog" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 352c409..b7ad1e9 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -567,6 +567,11 @@
     <string name="permdesc_interactAcrossUsersFull">Allows all possible interactions across
         users.</string>
 
+    <!--  Title of an application permission, listed so the user can choose whether they want to allow the application to create/remove/query users. [CHAR LIMIT=none] -->
+    <string name="permlab_manageUsers">manage users</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to create/remove/query users. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_manageUsers">Allows apps to manage users on the device, including query, creation and deletion.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=50] -->
     <string name="permlab_getDetailedTasks">retrieve details of running apps</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
@@ -3634,4 +3639,9 @@
     <!-- Content description of a MediaRouteButton for accessibility support -->
     <string name="media_route_button_content_description">Media output</string>
 
+    <!-- Display manager service -->
+
+    <!-- Name of the built-in display.  [CHAR LIMIT=50] -->
+    <string name="display_manager_built_in_display">Built-in Screen</string>
+
 </resources>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
index 6630601..216344d 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -500,19 +500,15 @@
         log("Turn screen off");
         PowerManager pm =
             (PowerManager) getSystemService(Context.POWER_SERVICE);
-        pm.goToSleep(SystemClock.uptimeMillis() + 100);
+        pm.goToSleep(SystemClock.uptimeMillis());
     }
 
     // Turn screen on
     public void turnScreenOn() {
         log("Turn screen on");
-        IPowerManager mPowerManagerService = IPowerManager.Stub.asInterface(
-                ServiceManager.getService("power"));;
-        try {
-            mPowerManagerService.userActivityWithForce(SystemClock.uptimeMillis(), false, true);
-        } catch (Exception e) {
-            log(e.toString());
-        }
+        PowerManager pm =
+                (PowerManager) getSystemService(Context.POWER_SERVICE);
+        pm.wakeUp(SystemClock.uptimeMillis());
     }
 
     /**
diff --git a/core/tests/coretests/src/android/content/pm/AppCacheTest.java b/core/tests/coretests/src/android/content/pm/AppCacheTest.java
index 0c31e2d..aae55e8 100755
--- a/core/tests/coretests/src/android/content/pm/AppCacheTest.java
+++ b/core/tests/coretests/src/android/content/pm/AppCacheTest.java
@@ -24,7 +24,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StatFs;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
@@ -570,7 +570,7 @@
             PackageStatsObserver observer = new PackageStatsObserver();
             //wait on observer
             synchronized(observer) {
-                getPm().getPackageSizeInfo(packageName, observer);
+                getPm().getPackageSizeInfo(packageName, UserHandle.myUserId(), observer);
                 long waitTime = 0;
                 while((!observer.isDone()) || (waitTime > MAX_WAIT_TIME) ) {
                     observer.wait(WAIT_TIME_INCR);
@@ -719,7 +719,7 @@
     File getDataDir() {
         try {
             ApplicationInfo appInfo = getPm().getApplicationInfo(mContext.getPackageName(), 0,
-                    UserId.myUserId());
+                    UserHandle.myUserId());
             return new File(appInfo.dataDir);
         } catch (RemoteException e) {
             throw new RuntimeException("Pacakge manager dead", e);
@@ -748,7 +748,7 @@
     
     @LargeTest
     public void testClearApplicationUserDataNoObserver() throws Exception {
-        getPm().clearApplicationUserData(mContext.getPackageName(), null, UserId.myUserId());
+        getPm().clearApplicationUserData(mContext.getPackageName(), null, UserHandle.myUserId());
         //sleep for 1 minute
         Thread.sleep(60*1000);
         //confirm files dont exist
diff --git a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
new file mode 100644
index 0000000..b814e2d
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.content.pm;
+
+import android.content.pm.ManifestDigest;
+import android.content.pm.VerificationParams;
+import android.net.Uri;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+
+/**
+ * Tests the android.content.pm.VerificationParams class
+ *
+ * To test run:
+ * ./development/testrunner/runtest.py frameworks-core -c android.content.pm.VerificationParamsTest
+ */
+public class VerificationParamsTest extends AndroidTestCase {
+
+    private final static String VERIFICATION_URI_STRING = "http://verification.uri/path";
+    private final static String ORIGINATING_URI_STRING = "http://originating.uri/path";
+    private final static String REFERRER_STRING = "http://referrer.uri/path";
+    private final static byte[] DIGEST_BYTES = "fake digest".getBytes();
+
+    private final static Uri VERIFICATION_URI = Uri.parse(VERIFICATION_URI_STRING);
+    private final static Uri ORIGINATING_URI = Uri.parse(ORIGINATING_URI_STRING);
+    private final static Uri REFERRER = Uri.parse(REFERRER_STRING);
+
+    private final static ManifestDigest MANIFEST_DIGEST = new ManifestDigest(DIGEST_BYTES);
+
+    public void testParcel() throws Exception {
+        VerificationParams expected = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
+                REFERRER, MANIFEST_DIGEST);
+
+        Parcel parcel = Parcel.obtain();
+        expected.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        VerificationParams actual = VerificationParams.CREATOR.createFromParcel(parcel);
+
+        assertEquals(VERIFICATION_URI, actual.getVerificationURI());
+
+        assertEquals(ORIGINATING_URI, actual.getOriginatingURI());
+
+        assertEquals(REFERRER, actual.getReferrer());
+
+        assertEquals(MANIFEST_DIGEST, actual.getManifestDigest());
+    }
+
+    public void testEquals_Success() throws Exception {
+        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
+                REFERRER, MANIFEST_DIGEST);
+
+        VerificationParams params2 = new VerificationParams(
+                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
+                Uri.parse(REFERRER_STRING), new ManifestDigest(DIGEST_BYTES));
+
+        assertEquals(params1, params2);
+    }
+
+    public void testEquals_VerificationUri_Failure() throws Exception {
+        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
+            REFERRER, MANIFEST_DIGEST);
+
+        VerificationParams params2 = new VerificationParams(
+                Uri.parse("http://a.different.uri/"), Uri.parse(ORIGINATING_URI_STRING),
+                Uri.parse(REFERRER_STRING), new ManifestDigest(DIGEST_BYTES));
+
+        assertFalse(params1.equals(params2));
+    }
+
+    public void testEquals_OriginatingUri_Failure() throws Exception {
+        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
+                REFERRER, MANIFEST_DIGEST);
+
+        VerificationParams params2 = new VerificationParams(
+                Uri.parse(VERIFICATION_URI_STRING), Uri.parse("http://a.different.uri/"),
+                Uri.parse(REFERRER_STRING), new ManifestDigest(DIGEST_BYTES));
+
+        assertFalse(params1.equals(params2));
+    }
+
+    public void testEquals_Referrer_Failure() throws Exception {
+        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
+                REFERRER, MANIFEST_DIGEST);
+
+        VerificationParams params2 = new VerificationParams(
+                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
+                Uri.parse("http://a.different.uri/"), new ManifestDigest(DIGEST_BYTES));
+
+        assertFalse(params1.equals(params2));
+    }
+
+    public void testEquals_ManifestDigest_Failure() throws Exception {
+        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
+                REFERRER, MANIFEST_DIGEST);
+
+        VerificationParams params2 = new VerificationParams(
+                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
+                Uri.parse(REFERRER_STRING), new ManifestDigest("a different digest".getBytes()));
+
+        assertFalse(params1.equals(params2));
+    }
+
+    public void testHashCode_Success() throws Exception {
+        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
+                REFERRER, MANIFEST_DIGEST);
+
+        VerificationParams params2 = new VerificationParams(
+                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
+                Uri.parse(REFERRER_STRING), new ManifestDigest(DIGEST_BYTES));
+
+        assertEquals(params1.hashCode(), params2.hashCode());
+    }
+
+    public void testHashCode_VerificationUri_Failure() throws Exception {
+        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
+                REFERRER, MANIFEST_DIGEST);
+
+        VerificationParams params2 = new VerificationParams(null, Uri.parse(ORIGINATING_URI_STRING),
+                Uri.parse(REFERRER_STRING), new ManifestDigest(DIGEST_BYTES));
+
+        assertFalse(params1.hashCode() == params2.hashCode());
+    }
+
+    public void testHashCode_OriginatingUri_Failure() throws Exception {
+        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
+                REFERRER, MANIFEST_DIGEST);
+
+        VerificationParams params2 = new VerificationParams(
+                Uri.parse(VERIFICATION_URI_STRING), Uri.parse("http://a.different.uri/"),
+                Uri.parse(REFERRER_STRING), new ManifestDigest(DIGEST_BYTES));
+
+        assertFalse(params1.hashCode() == params2.hashCode());
+    }
+
+    public void testHashCode_Referrer_Failure() throws Exception {
+        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
+                REFERRER, MANIFEST_DIGEST);
+
+        VerificationParams params2 = new VerificationParams(
+                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING), null,
+                new ManifestDigest(DIGEST_BYTES));
+
+        assertFalse(params1.hashCode() == params2.hashCode());
+    }
+
+    public void testHashCode_ManifestDigest_Failure() throws Exception {
+        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
+                REFERRER, MANIFEST_DIGEST);
+
+        VerificationParams params2 = new VerificationParams(
+                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
+                Uri.parse(REFERRER_STRING), new ManifestDigest("a different digest".getBytes()));
+
+        assertFalse(params1.hashCode() == params2.hashCode());
+    }
+}
diff --git a/core/tests/coretests/src/android/os/BrightnessLimit.java b/core/tests/coretests/src/android/os/BrightnessLimit.java
index 5e9b906..f4a5e09 100644
--- a/core/tests/coretests/src/android/os/BrightnessLimit.java
+++ b/core/tests/coretests/src/android/os/BrightnessLimit.java
@@ -49,7 +49,7 @@
                 ServiceManager.getService("power"));
         if (power != null) {
             try {
-                power.setBacklightBrightness(0);
+                power.setTemporaryScreenBrightnessSettingOverride(0);
             } catch (RemoteException darn) {
                 
             }
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index f12cbe1..4d0b892 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -17,21 +17,13 @@
 package android.os;
 
 import android.content.Context;
-import android.os.FileUtils;
-import android.os.FileUtils.FileStatus;
 import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
-import java.io.FileWriter;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
-import java.io.IOException;
-
-import junit.framework.Assert;
+import java.io.FileWriter;
 
 public class FileUtilsTest extends AndroidTestCase {
     private static final String TEST_DATA =
@@ -60,60 +52,6 @@
         if (mCopyFile.exists()) mCopyFile.delete();
     }
 
-    @LargeTest
-    public void testGetFileStatus() {
-        final byte[] MAGIC = { 0xB, 0xE, 0x0, 0x5 };
-
-        try {
-            // truncate test file and write MAGIC (4 bytes) to it.
-            FileOutputStream os = new FileOutputStream(mTestFile, false);
-            os.write(MAGIC, 0, 4);
-            os.flush();
-            os.close();
-        } catch (FileNotFoundException e) {
-            Assert.fail("File was removed durning test" + e);
-        } catch (IOException e) {
-            Assert.fail("Unexpected IOException: " + e);
-        }
-        
-        Assert.assertTrue(mTestFile.exists());
-        Assert.assertTrue(FileUtils.getFileStatus(mTestFile.getPath(), null));
-        
-        FileStatus status1 = new FileStatus();
-        FileUtils.getFileStatus(mTestFile.getPath(), status1);
-        
-        Assert.assertEquals(4, status1.size);
-        
-        // Sleep for at least one second so that the modification time will be different.
-        try {
-            Thread.sleep(1000);
-        } catch (InterruptedException e) {
-        }
-
-        try {
-            // append so we don't change the creation time.
-            FileOutputStream os = new FileOutputStream(mTestFile, true);
-            os.write(MAGIC, 0, 4);
-            os.flush();
-            os.close();
-        } catch (FileNotFoundException e) {
-            Assert.fail("File was removed durning test" + e);
-        } catch (IOException e) {
-            Assert.fail("Unexpected IOException: " + e);
-        }
-        
-        FileStatus status2 = new FileStatus();
-        FileUtils.getFileStatus(mTestFile.getPath(), status2);
-        
-        Assert.assertEquals(8, status2.size);
-        Assert.assertTrue(status2.mtime > status1.mtime);
-        
-        mTestFile.delete();
-        
-        Assert.assertFalse(mTestFile.exists());
-        Assert.assertFalse(FileUtils.getFileStatus(mTestFile.getPath(), null));
-    }
-
     // TODO: test setPermissions(), getPermissions()
 
     @MediumTest
diff --git a/core/tests/coretests/src/android/os/ProcessTest.java b/core/tests/coretests/src/android/os/ProcessTest.java
new file mode 100644
index 0000000..1f5b7c8
--- /dev/null
+++ b/core/tests/coretests/src/android/os/ProcessTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.os;
+
+import android.os.Process;
+import android.os.UserHandle;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+
+public class ProcessTest extends TestCase {
+
+    @MediumTest
+    public void testProcessGetUidFromName() throws Exception {
+        assertEquals(android.os.Process.SYSTEM_UID, Process.getUidForName("system"));
+        assertEquals(Process.BLUETOOTH_UID, Process.getUidForName("bluetooth"));
+        assertEquals(Process.FIRST_APPLICATION_UID, Process.getUidForName("u0_a0"));
+        assertEquals(UserHandle.getUid(1, Process.SYSTEM_UID), Process.getUidForName("u1_system"));
+        assertEquals(UserHandle.getUid(2, Process.FIRST_ISOLATED_UID),
+                Process.getUidForName("u2_i0"));
+        assertEquals(UserHandle.getUid(3, Process.FIRST_APPLICATION_UID + 100),
+                Process.getUidForName("u3_a100"));
+    }
+
+    @MediumTest
+    public void testProcessGetUidFromNameFailure() throws Exception {
+        // Failure cases
+        assertEquals(-1, Process.getUidForName("u2a_foo"));
+        assertEquals(-1, Process.getUidForName("u1_abcdef"));
+        assertEquals(-1, Process.getUidForName("u23"));
+        assertEquals(-1, Process.getUidForName("u2_i34a"));
+        assertEquals(-1, Process.getUidForName("akjhwiuefhiuhsf"));
+        assertEquals(-1, Process.getUidForName("u5_radio5"));
+        assertEquals(-1, Process.getUidForName("u2jhsajhfkjhsafkhskafhkashfkjashfkjhaskjfdhakj3"));
+    }
+
+}
diff --git a/data/etc/Android.mk b/data/etc/Android.mk
index 71a9a15..134ac0c 100644
--- a/data/etc/Android.mk
+++ b/data/etc/Android.mk
@@ -21,8 +21,6 @@
 
 LOCAL_MODULE := platform.xml
 
-LOCAL_MODULE_TAGS := user
-
 LOCAL_MODULE_CLASS := ETC
 
 # This will install the file in /system/etc/permissions
@@ -38,8 +36,6 @@
 
 #LOCAL_MODULE := required_hardware.xml
 
-#LOCAL_MODULE_TAGS := user
-
 #LOCAL_MODULE_CLASS := ETC
 
 # This will install the file in /system/etc/permissions
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 3d6c9d3..7bc172c 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -76,14 +76,6 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
 include $(BUILD_PREBUILT)
 
-include $(CLEAR_VARS)
-LOCAL_MODULE := fallback_fonts-ja.xml
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
-include $(BUILD_PREBUILT)
-
 droidsans_fallback_src := DroidSansFallbackFull.ttf
 extra_font_files := \
 	DroidSans.ttf \
@@ -91,8 +83,7 @@
 	DroidSansEthiopic-Regular.ttf \
 	DroidSansTamil-Regular.ttf \
 	DroidSansTamil-Bold.ttf \
-	MTLmr3m.ttf \
-	fallback_fonts-ja.xml
+	MTLmr3m.ttf
 endif  # SMALLER_FONT_FOOTPRINT
 
 ################################
diff --git a/data/fonts/fallback_fonts-ja.xml b/data/fonts/fallback_fonts-ja.xml
deleted file mode 100644
index 82e3a38..0000000
--- a/data/fonts/fallback_fonts-ja.xml
+++ /dev/null
@@ -1,121 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    Fallback Fonts
-
-    This file specifies the fonts, and the priority order, that will be searched for any
-    glyphs not handled by the default fonts specified in /system/etc/system_fonts.xml.
-    Each entry consists of a family tag and a list of files (file names) which support that
-    family. The fonts for each family are listed in the order of the styles that they
-    handle (the order is: regular, bold, italic, and bold-italic). The order in which the
-    families are listed in this file represents the order in which these fallback fonts
-    will be searched for glyphs that are not supported by the default system fonts (which are
-    found in /system/etc/system_fonts.xml).
-
-    Note that there is not nameset for fallback fonts, unlike the fonts specified in
-    system_fonts.xml. The ability to support specific names in fallback fonts may be supported
-    in the future. For now, the lack of files entries here is an indicator to the system that
-    these are fallback fonts, instead of default named system fonts.
-
-    There is another optional file in /vendor/etc/fallback_fonts.xml. That file can be used to
-    provide references to other font families that should be used in addition to the default
-    fallback fonts. That file can also specify the order in which the fallback fonts should be
-    searched, to ensure that a vendor-provided font will be used before another fallback font
-    which happens to handle the same glyph.
-
-    Han languages (Chinese, Japanese, and Korean) share a common range of unicode characters;
-    their ordering in the fallback or vendor files gives priority to the first in the list.
-    Locale-specific ordering can be configured by adding language and region codes to the end
-    of the filename (e.g. /system/etc/fallback_fonts-ja.xml). When no region code is used,
-    as with this example, all regions are matched. Use separate files for each supported locale.
-    The standard fallback file (fallback_fonts.xml) is used when a locale does not have its own
-    file. All fallback files must contain the same complete set of fonts; only their ordering
-    can differ.
--->
-<familyset>
-    <family>
-        <fileset>
-            <file variant="elegant">DroidNaskh-Regular.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
-            <file variant="compact">DroidNaskh-Regular-SystemUI.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
-            <file>DroidSansEthiopic-Regular.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
-            <file>DroidSansHebrew-Regular.ttf</file>
-            <file>DroidSansHebrew-Bold.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
-            <file>DroidSansThai.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
-            <file>DroidSansArmenian.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
-            <file>DroidSansGeorgian.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
-            <file>DroidSansDevanagari-Regular.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
-            <file>DroidSansTamil-Regular.ttf</file>
-            <file>DroidSansTamil-Bold.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
-            <file>AnjaliNewLipi-light.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
-            <file>Lohit-Bengali.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
-            <file>Lohit-Kannada.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
-            <file>AndroidEmoji.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
-            <file>MTLmr3m.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
-            <file>DroidSansFallback.ttf</file>
-        </fileset>
-    </family>
-    <!--
-        Fonts below this point have problematic glyphs and should not be moved
-        higher in the fallback list until those glyphs have been fixed.
-    -->
-    <family>
-        <fileset>
-            <file>Lohit-Telugu.ttf</file> <!-- masks U+FFBC-10007 -->
-        </fileset>
-    </family>
-</familyset>
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 758adb5..2c9a0c8 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -24,12 +24,9 @@
 
     Han languages (Chinese, Japanese, and Korean) share a common range of unicode characters;
     their ordering in the fallback or vendor files gives priority to the first in the list.
-    Locale-specific ordering can be configured by adding language and region codes to the end
-    of the filename (e.g. /system/etc/fallback_fonts-ja.xml). When no region code is used,
-    as with this example, all regions are matched. Use separate files for each supported locale.
-    The standard fallback file (fallback_fonts.xml) is used when a locale does not have its own
-    file. All fallback files must contain the same complete set of fonts; only their ordering
-    can differ.
+    Language-specific ordering can be configured by adding a BCP 47-style "lang" attribute to
+    a "file" element; fonts matching the language of text being drawn will be prioritised over
+    all others.
 -->
 <familyset>
     <family>
@@ -106,7 +103,7 @@
     </family>
     <family>
         <fileset>
-            <file>MTLmr3m.ttf</file>
+            <file lang="ja">MTLmr3m.ttf</file>
         </fileset>
     </family>
     <!--
diff --git a/data/fonts/vendor_fonts.xml b/data/fonts/vendor_fonts.xml
index 5850f94..8690ee1 100644
--- a/data/fonts/vendor_fonts.xml
+++ b/data/fonts/vendor_fonts.xml
@@ -7,8 +7,7 @@
     that in your makefile, this directory should be referenced as $(TARGET_COPY_OUT_VENDOR)/etc/:
 
         PRODUCT_COPY_FILES += \
-            frameworks/base/data/fonts/vendor_fonts.xml:$(TARGET_COPY_OUT_VENDOR)/etc/fallback_fonts.xml \
-            frameworks/base/data/fonts/vendor_fonts-ja.xml:$(TARGET_COPY_OUT_VENDOR)/etc/fallback_fonts-ja.xml
+            frameworks/base/data/fonts/vendor_fonts.xml:$(TARGET_COPY_OUT_VENDOR)/etc/fallback_fonts.xml
 
     For example, vendors might want to build configurations for locales that are
     better served by fonts which either handle glyphs not supported in the default fonts or which
@@ -32,32 +31,9 @@
 
     Han languages (Chinese, Japanese, and Korean) share a common range of unicode characters;
     their ordering in the fallback or vendor files gives priority to the first in the list.
-    Locale-specific ordering can be configured by adding language and region codes to the end
-    of the filename (e.g. /vendor/etc/fallback_fonts-ja.xml). When no region code is used,
-    as with this example, all regions are matched. Use separate files for each supported locale.
-    The standard fallback file (fallback_fonts.xml) is used when a locale does not have its own
-    file. All fallback files must contain the same complete set of fonts; only their ordering
-    can differ. For example, on a device supporting Japanese, but with English as the default,
-    /vendor/etc/fallback_fonts.xml might contain:
-
-        <familyset>
-            <family>
-                <fileset>
-                    <file>DroidSansJapanese.ttf</file>
-                </fileset>
-            </family>
-        </familyset>
-
-    placing the Japanese font at the end of the fallback sequence for English, with a corresponding
-    /system/vendor/etc/fallback_fonts-ja.xml, placing it at the front of the list.
-
-        <familyset>
-            <family order="0">
-                <fileset>
-                    <file>DroidSansJapanese.ttf</file>
-                </fileset>
-            </family>
-        </familyset>
+    Language-specific ordering can be configured by adding a BCP 47-style "lang" attribute to
+    a "file" element; fonts matching the language of text being drawn will be prioritised over
+    all others.
 
     The sample configuration below is an example of how one might provide two families of fonts
     that get inserted at the first and second (0  and 1) position in the overall fallback fonts.
@@ -82,4 +58,4 @@
         </fileset>
     </family>
 </familyset>
--->
\ No newline at end of file
+--->
diff --git a/docs/downloads/design/Android_Design_Downloads_20120229.zip b/docs/downloads/design/Android_Design_Downloads_20120229.zip
deleted file mode 100644
index 7bbd85f..0000000
--- a/docs/downloads/design/Android_Design_Downloads_20120229.zip
+++ /dev/null
Binary files differ
diff --git a/docs/downloads/design/Android_Design_Downloads_20120814.zip b/docs/downloads/design/Android_Design_Downloads_20120814.zip
new file mode 100755
index 0000000..102b011
--- /dev/null
+++ b/docs/downloads/design/Android_Design_Downloads_20120814.zip
Binary files differ
diff --git a/docs/downloads/design/Android_Design_Fireworks_Stencil_20120229.png b/docs/downloads/design/Android_Design_Fireworks_Stencil_20120229.png
deleted file mode 100644
index 5136379..0000000
--- a/docs/downloads/design/Android_Design_Fireworks_Stencil_20120229.png
+++ /dev/null
Binary files differ
diff --git a/docs/downloads/design/Android_Design_Fireworks_Stencil_20120814.png b/docs/downloads/design/Android_Design_Fireworks_Stencil_20120814.png
new file mode 100755
index 0000000..9a55143
--- /dev/null
+++ b/docs/downloads/design/Android_Design_Fireworks_Stencil_20120814.png
Binary files differ
diff --git a/docs/downloads/design/Android_Design_Holo_Widgets_20120302.zip b/docs/downloads/design/Android_Design_Holo_Widgets_20120302.zip
deleted file mode 100644
index 90c45c6..0000000
--- a/docs/downloads/design/Android_Design_Holo_Widgets_20120302.zip
+++ /dev/null
Binary files differ
diff --git a/docs/downloads/design/Android_Design_Holo_Widgets_20120814.zip b/docs/downloads/design/Android_Design_Holo_Widgets_20120814.zip
new file mode 100755
index 0000000..295affd
--- /dev/null
+++ b/docs/downloads/design/Android_Design_Holo_Widgets_20120814.zip
Binary files differ
diff --git a/docs/downloads/design/Android_Design_Icons_20120229.zip b/docs/downloads/design/Android_Design_Icons_20120229.zip
deleted file mode 100644
index c2728f3..0000000
--- a/docs/downloads/design/Android_Design_Icons_20120229.zip
+++ /dev/null
Binary files differ
diff --git a/docs/downloads/design/Android_Design_Icons_20120814.zip b/docs/downloads/design/Android_Design_Icons_20120814.zip
new file mode 100755
index 0000000..3471438
--- /dev/null
+++ b/docs/downloads/design/Android_Design_Icons_20120814.zip
Binary files differ
diff --git a/docs/downloads/design/Android_Design_Illustrator_Vectors_20120814.ai b/docs/downloads/design/Android_Design_Illustrator_Vectors_20120814.ai
new file mode 100644
index 0000000..928ecfa
--- /dev/null
+++ b/docs/downloads/design/Android_Design_Illustrator_Vectors_20120814.ai
Binary files differ
diff --git a/docs/downloads/design/Android_Design_OmniGraffle_Stencil_20120229.graffle b/docs/downloads/design/Android_Design_OmniGraffle_Stencil_20120229.graffle
deleted file mode 100644
index 9e418d3..0000000
--- a/docs/downloads/design/Android_Design_OmniGraffle_Stencil_20120229.graffle
+++ /dev/null
Binary files differ
diff --git a/docs/downloads/design/Android_Design_OmniGraffle_Stencil_20120814.graffle b/docs/downloads/design/Android_Design_OmniGraffle_Stencil_20120814.graffle
new file mode 100755
index 0000000..d575008
--- /dev/null
+++ b/docs/downloads/design/Android_Design_OmniGraffle_Stencil_20120814.graffle
Binary files differ
diff --git a/docs/html/design/building-blocks/dialogs.jd b/docs/html/design/building-blocks/dialogs.jd
index 9b653ee..728821e 100644
--- a/docs/html/design/building-blocks/dialogs.jd
+++ b/docs/html/design/building-blocks/dialogs.jd
@@ -10,28 +10,29 @@
 <div class="with-callouts">
 
 <ol>
-<li>
-<h4>Optional title region</h4>
-<p>The title introduces the content of your dialog. It can, for example, identify the name of a
- setting that the user is about to change, or request a decision.</p>
-</li>
-<li>
-<h4>Content area</h4>
-<p>Dialog content varies widely. For settings dialogs, a dialog may contain UI elements such as
- sliders, text fields, checkboxes, or radio buttons that allow the user to change app or system
- settings. In other cases, such as alerts, the content may consist solely of text that provides
- further context for a user decision.</p>
-</li>
-<li>
-<h4>Action buttons</h4>
-<p>Action buttons are typically Cancel and/or OK, with OK indicating the preferred or most likely
- action. However, if the options consist of specific actions such as Close or Wait rather than
- a confirmation or cancellation of the action described in the content, then all the buttons
- should be active verbs. As a rule, the dismissive action of a dialog is always on the left
- whereas the affirmative actions are on the right.</p>
-</li>
-</ol>
+  <li>
+  <h4>Optional title region</h4>
+  <p>The title introduces the content of your dialog. It can, for example, identify the name of a
+   setting that the user is about to change, or request a decision.</p>
+  </li>
+  <li>
+  <h4>Content area</h4>
+  <p>Dialog content varies widely. For settings dialogs, a dialog may contain UI elements such as
+   sliders, text fields, checkboxes, or radio buttons that allow the user to change app or system
+   settings. In other cases, such as alerts, the content may consist solely of text that provides
+   further context for a user decision.</p>
+  </li>
 
+  <li>
+  <h4>Action buttons</h4>
+  <p>Action buttons are typically Cancel and/or OK, with OK indicating the preferred or most likely action. However, if the options consist of specific actions such as Close or Wait rather than a confirmation or cancellation of the action described in the content, then all the buttons should be active verbs. Order actions following these rules:</p>
+    <ul>
+    
+    <li>The dismissive action of a dialog is always on the left. Dismissive actions return to the user to the previous state.</li>
+    <li>The affirmative actions are on the right. Affirmative actions continue progress toward the user goal that triggered the dialog.</li>
+    </ul>
+  </li>
+</ol>
 </div>
 
 <img src="{@docRoot}design/media/dialogs_examples.png">
@@ -80,7 +81,46 @@
 
   </div>
 </div>
+<p>When crafting a confirmation dialog, make the title meaningful by echoing the requested action.</p>
 
+<div class="layout-content-row">
+  <div class="layout-content-col span-4">
+    <div class="do-dont-label bad">Don't</div>
+      <table class="ui-table bad">
+      <thead>
+        <tr>
+          <th class="label">
+          Are you sure?
+          </th>
+        </tr>
+      </thead>
+      </table>
+  </div>
+  <div class="layout-content-col span-4">
+    <div class="do-dont-label bad">Don't</div>
+      <table class="ui-table bad">
+      <thead>
+        <tr>
+          <th class="label">
+          Warning!
+          </th>
+        </tr>
+      </thead>
+      </table>
+  </div>
+  <div class="layout-content-col span-5">
+    <div class="do-dont-label good">Do</div>
+      <table class="ui-table good">
+      <thead>
+        <tr>
+          <th class="label">
+          Erase USB storage?
+          </th>
+        </tr>
+      </thead>
+      </table>
+  </div>
+</div>
 
 <h2 id="popups">Popups</h2>
 
diff --git a/docs/html/design/building-blocks/index.jd b/docs/html/design/building-blocks/index.jd
index d915aae..e554775 100644
--- a/docs/html/design/building-blocks/index.jd
+++ b/docs/html/design/building-blocks/index.jd
@@ -11,7 +11,7 @@
 #text-overlay {
   position: absolute;
   left: 0;
-  top: 472px;
+  top: 520px;
   width: 450px;
 }
 </style>
diff --git a/docs/html/design/building-blocks/progress.jd b/docs/html/design/building-blocks/progress.jd
index 03fc09c..7342387 100644
--- a/docs/html/design/building-blocks/progress.jd
+++ b/docs/html/design/building-blocks/progress.jd
@@ -1,19 +1,14 @@
-page.title=Progress and Activity
+page.title=Progress &amp; Activity
 @jd:body
 
-<p>When an operation of interest to the user is taking place over a relatively long period of time,
-provide visual feedback that it's still happening and in the process of being completed.</p>
-<h2 id="progress">Progress</h2>
+<p>Progress bars and activity indicators signal to users that something is happening that will take a moment.</p>
+<h2 id="progress">Progress bars</h2>
 
-<p>If you know the percentage of the operation that has been completed, use a determinate progress bar
-to give the user a sense of how much longer it will take.</p>
+<p>Progress bars are for situations where the percentage completed can be determined. They give users a quick sense of how much longer an operation will take.</p>
 
 <img src="{@docRoot}design/media/progress_download.png">
 
-<p>The progress bar should always travel from 0% to 100% completion. Avoid setting the bar to a lower
-value than a previous value, or using the same progress bar to represent the progress of multiple
-events, since doing so makes the display meaningless. If you're not sure how long a particular
-operation will take, use an indeterminate progress indicator.</p>
+<p>A progress bar should always fill from 0% to 100% and never move backwards to a lower value. If multiple operations are happening in sequence, use the progress bar to represent the delay as a whole, so that when the bar reaches 100%, it doesn't return back to 0%.</p>
 
 <div class="vspace size-2">&nbsp;</div>
 
@@ -22,12 +17,11 @@
   Progress bar in Holo Dark and Holo Light.
 </div>
 
-<h2 id="activity">Activity</h2>
+<h2 id="activity">Activity indicators</h2>
 
-<p>If you don't know how much longer an operation will continue, use an indeterminate progress
-indicator. There are two styles available: a flat bar and a circle. Use the one that best fits the
-available space.</p>
+<p>Activity indicators are for operations of an indeterminate length. They ask users to wait a moment while something finishes up, without getting into specifics about what's happening behind the scenes.</p>
 
+<p>Two styles are available: a bar and a circle. Each is offered in a variety of sizes, in both Holo Light and Holo Dark themes. Choose the appropriate style and size for the surrounding context. For example, the largest activity circle works well when displayed in a blank content area, but not in a smaller dialog box. Each operation should only be represented by one activity indicator.</p>
 
 <div class="layout-content-row">
   <div class="layout-content-col span-6">
@@ -38,14 +32,8 @@
   <div class="layout-content-col span-7 with-callouts">
 
     <ol>
-      <li class="value-1"><h4>Activity bar (shown with the Holo Dark theme)</h4>
-        <p>
-
-An indeterminate activity bar is used at the start of an application download because the Play Store
-app hasn't been able to contact the server yet, and it's not possible to determine how long it will
-take for the download to begin.
-
-        </p>
+      <li class="value-1"><h4>Activity bar</h4>
+        <p>In this example, an activity bar (in Holo Dark) appears when a user first requests a download. There's an unknown period of time when the download has not yet started. As soon as the download starts, this activity bar transforms into a progress bar.</p>
       </li>
     </ol>
 
@@ -61,12 +49,19 @@
   <div class="layout-content-col span-7 with-callouts">
 
     <ol>
-      <li class="value-2"><h4>Activity circle (shown with the Holo Light theme)</h4>
+      <li class="value-2"><h4>Activity circle</h4>
+        <p>In this example, an activity circle (in Holo Light) is used in the Gmail application when a message is being loaded because it's not possible to determine how long it will take to download the email.</p>
+        <p>When displaying an activity circle, do not include text to communicate what the app is doing. The moving circle alone provides sufficient feedback about the delay, and does so in an understated way that minimizes the impact.</p>
         <p>
-
-An indeterminate activity circle is used in the Gmail application when a message is being
-loaded because it's not possible to determine how long it will take to download the email.
-
+        <div class="layout-content-col span-3" style="margin-left:0">
+          <div class="do-dont-label bad">Don't</div>
+          <img src="{@docRoot}design/media/progress_activity_dont.png">
+        </div>
+      
+        <div class="layout-content-col span-3">
+          <div class="do-dont-label good">Do</div>
+          <img src="{@docRoot}design/media/progress_activity_do.png">
+        </div>
         </p>
       </li>
     </ol>
@@ -74,6 +69,34 @@
   </div>
 </div>
 
-<p>You should only use one activity indicator on screen per activity, and it should appropriately sized
-for the surrounding context. For example, the largest activity circle works well when displayed in a
-blank content area, but not in a smaller dialog box.</p>
+<h2 id="custom-indicators">Custom indicators</h2>
+<p>The standard progress bar and activity indicators work well for most situations and should be used whenever possible to provide a consistent experience across Android. However, some situations may call for something more custom.</p>
+
+<p>Here's an example:<br>
+In all of the Google Play apps (Music, Books, Movies, Magazines), we wanted the current download state of each item to be visible at all times at the top-level screen. These states are:
+  <ul>
+    <li>Not downloaded</li>
+    <li>Temporarily downloaded (automatically cached by the app)</li>
+    <li>Permanently downloaded on the device at the user's request</li>
+  </ul>
+</p>
+<p>We also needed to indicate progress from one download state to another, because downloading is not instantaneous.</p>
+<p>This presented a challenge, because the Google Play apps use a variety of different layouts, and some of them are highly space-constrained. We didn't want this information to clutter the top-level screens, or compete too much with the cover art.</p>
+<p>So we designed a custom indicator that could show all of the information in a tiny footprint, with the flexibility to appear on top of content if necessary.</p>
+
+<img src="{@docRoot}design/media/progress_activity_custom.png">
+
+<p>The color indicates whether it's downloaded (blue) or not (gray). The appearance of the pin indicates whether the download is permanent (white, upright) or temporary (gray, diagonal). And when state is in the process of changing, progress is indicated by a moving pie chart.</p>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-9">
+    <img src="{@docRoot}design/media/progress_activity_custom_app.png">
+  </div>
+  <div class="layout-content-col span-4">
+    <div class="figure-caption">
+      Across Google Play apps with different layouts, the same custom indicator appears with each item. It communicates download state as well as progress, in a compact package that can be incorporated into any screen design.
+    </div>
+  </div>
+</div>
+
+<p>If you find that the standard indicators aren't meeting your needs (due to space constraints, state complexities), by all means design your own. Make it feel like part of the Android family by injecting some of the visual characteristics of the standard indicators. In this example, we carried over the circular shape, the same shade of blue, and the flat and simple style.</p>
diff --git a/docs/html/design/building-blocks/tabs.jd b/docs/html/design/building-blocks/tabs.jd
index 19ed1c3..fe05f80 100644
--- a/docs/html/design/building-blocks/tabs.jd
+++ b/docs/html/design/building-blocks/tabs.jd
@@ -6,6 +6,7 @@
 <p>Tabs in the action bar make it easy to explore and switch between different views or functional
 aspects of your app, or to browse categorized data sets.</p>
 
+<p>For details on using gestures to move between tabs, see the <a href="{@docRoot}design/patterns/swipe-views.html">Swipe Views</a> pattern.</p>
 
 <h2 id="scrollable">Scrollable Tabs</h2>
 
@@ -34,9 +35,8 @@
 
 
 <h2 id="fixed">Fixed Tabs</h2>
-
-
-<p>Fixed tabs display all items concurrently. To navigate to a different view, touch the tab.</p>
+<p>Fixed tabs display all items concurrently. To navigate to a different view, touch the tab, or swipe left or right.</p>
+<p>Fixed tabs are displayed with equal width, based on the width of the widest tab label. If there is insufficient room to display all tabs, the tab labels themselves will be scrollable. For this reason, fixed tabs are best suited for displaying 3 or fewer tabs.</p>
 
 <img src="{@docRoot}design/media/tabs_standard.png">
 <div class="figure-caption">
diff --git a/docs/html/design/design_toc.cs b/docs/html/design/design_toc.cs
index a31fdd3..c3020e1 100644
--- a/docs/html/design/design_toc.cs
+++ b/docs/html/design/design_toc.cs
@@ -26,7 +26,7 @@
   <li class="nav-section">
     <div class="nav-section-header"><a href="<?cs var:toroot ?>design/patterns/index.html">Patterns</a></div>
     <ul>
-      <li><a href="<?cs var:toroot ?>design/patterns/new-4-0.html">New in Android 4.0</a></li>
+      <li><a href="<?cs var:toroot ?>design/patterns/new.html">New in Android</a></li>
       <li><a href="<?cs var:toroot ?>design/patterns/gestures.html">Gestures</a></li>
       <li><a href="<?cs var:toroot ?>design/patterns/app-structure.html">App Structure</a></li>
       <li><a href="<?cs var:toroot ?>design/patterns/navigation.html">Navigation</a></li>
@@ -34,9 +34,13 @@
       <li><a href="<?cs var:toroot ?>design/patterns/multi-pane-layouts.html">Multi-pane Layouts</a></li>
       <li><a href="<?cs var:toroot ?>design/patterns/swipe-views.html">Swipe Views</a></li>
       <li><a href="<?cs var:toroot ?>design/patterns/selection.html">Selection</a></li>
+      <li><a href="<?cs var:toroot ?>design/patterns/confirming-acknowledging.html">Confirming &amp; Acknowledging</a></li>
       <li><a href="<?cs var:toroot ?>design/patterns/notifications.html">Notifications</a></li>
+      <li><a href="<?cs var:toroot ?>design/patterns/widgets.html">Widgets</a></li>
       <li><a href="<?cs var:toroot ?>design/patterns/settings.html">Settings</a></li>
+      <li><a href="<?cs var:toroot ?>design/patterns/help.html">Help</a></li>
       <li><a href="<?cs var:toroot ?>design/patterns/compatibility.html">Compatibility</a></li>
+      <li><a href="<?cs var:toroot ?>design/patterns/accessibility.html">Accessibility</a></li>
       <li><a href="<?cs var:toroot ?>design/patterns/pure-android.html">Pure Android</a></li>
     </ul>
   </li>
@@ -63,4 +67,8 @@
     <div class="nav-section-header empty"><a href="<?cs var:toroot ?>design/downloads/index.html">Downloads</a></div>
   </li>
 
+  <li class="nav-section">
+    <div class="nav-section-header empty"><a href="<?cs var:toroot ?>design/videos/index.html">Videos</a></div>
+  </li>
+
 </ul>
\ No newline at end of file
diff --git a/docs/html/design/downloads/index.jd b/docs/html/design/downloads/index.jd
index 67dfd79..4503098 100644
--- a/docs/html/design/downloads/index.jd
+++ b/docs/html/design/downloads/index.jd
@@ -12,7 +12,7 @@
   <div class="layout-content-col span-4">
 
 <p>
-  <a class="download-button" href="https://dl-ssl.google.com/android/design/Android_Design_Downloads_20120229.zip">Download All</a>
+  <a class="download-button" href="{@docRoot}downloads/design/Android_Design_Downloads_20120814.zip">Download All</a>
 </p>
 
   </div>
@@ -37,9 +37,10 @@
   <div class="layout-content-col span-4">
 
 <p>
-  <a class="download-button" href="https://dl-ssl.google.com/android/design/Android_Design_Fireworks_Stencil_20120229.png">Adobe&reg; Fireworks&reg; PNG Stencil</a>
-  <a class="download-button" href="https://dl-ssl.google.com/android/design/Android_Design_OmniGraffle_Stencil_20120229.graffle">Omni&reg; OmniGraffle&reg; Stencil</a>
-  <a class="download-button" href="https://dl-ssl.google.com/android/design/Android_Design_Holo_Widgets_20120302.zip">Adobe&reg; Photoshop&reg; Sources</a>
+  <a class="download-button" href="{@docRoot}downloads/design/Android_Design_Fireworks_Stencil_20120814.png">Adobe&reg; Fireworks&reg; PNG Stencil</a>
+  <a class="download-button" href="{@docRoot}downloads/design/Android_Design_Illustrator_Vectors_20120814.ai">Adobe&reg; Illustrator&reg; Stencil</a>
+  <a class="download-button" href="{@docRoot}downloads/design/Android_Design_OmniGraffle_Stencil_20120814.graffle">Omni&reg; OmniGraffle&reg; Stencil</a>
+  <a class="download-button" href="{@docRoot}downloads/design/Android_Design_Holo_Widgets_20120814.zip">Adobe&reg; Photoshop&reg; Sources</a>
 </p>
 
   </div>
@@ -65,7 +66,7 @@
   <div class="layout-content-col span-4">
 
 <p>
-  <a class="download-button" href="https://dl-ssl.google.com/android/design/Android_Design_Icons_20120229.zip">Action Bar Icon Pack</a>
+  <a class="download-button" href="{@docRoot}downloads/design/Android_Design_Icons_20120814.zip">Action Bar Icon Pack</a>
 </p>
 
   </div>
@@ -90,8 +91,8 @@
   <div class="layout-content-col span-4">
 
 <p>
-  <a class="download-button" href="https://dl-ssl.google.com/android/design/Roboto_Hinted_20111129.zip">Roboto</a>
-  <a class="download-button" href="https://dl-ssl.google.com/android/design/Roboto_Specimen_Book_20111129.pdf">Specimen Book</a>
+  <a class="download-button" href="{@docRoot}downloads/design/Roboto_Hinted_20111129.zip">Roboto</a>
+  <a class="download-button" href="{@docRoot}downloads/design/Roboto_Specimen_Book_20111129.pdf">Specimen Book</a>
 </p>
 
   </div>
@@ -114,7 +115,7 @@
   <div class="layout-content-col span-4">
 
 <p>
-  <a class="download-button" href="https://dl-ssl.google.com/android/design/Android_Design_Color_Swatches_20120229.zip">Color Swatches</a>
+  <a class="download-button" href="{@docRoot}downloads/design/Android_Design_Color_Swatches_20120229.zip">Color Swatches</a>
 </p>
 
   </div>
diff --git a/docs/html/design/get-started/creative-vision.jd b/docs/html/design/get-started/creative-vision.jd
index 792b97d..c57b185 100644
--- a/docs/html/design/get-started/creative-vision.jd
+++ b/docs/html/design/get-started/creative-vision.jd
@@ -5,13 +5,7 @@
 
 <div class="vspace size-1">&nbsp;</div>
 
-<p>Ice Cream Sandwich (Android 4.0) marks a major milestone for Android design. We touched nearly every
-pixel of the system as we expanded the new design approaches introduced in Honeycomb tablets to all
-types of mobile devices. Starting with the most basic elements, we introduced a new font, Roboto,
-designed for high-resolution displays. Other big changes include framework-level action bars on
-phones and support for new phones without physical buttons.</p>
-<p>We focused the design work with three overarching goals for our core apps and the system at large.
-As you design apps to work with Android, consider these goals:</p>
+<p>We focused the design of Android around three overarching goals, which apply to our core apps as well as the system at large. As you design apps to work with Android, consider these goals:</p>
 
 <div class="vspace size-1">&nbsp;</div>
 
diff --git a/docs/html/design/get-started/ui-overview.jd b/docs/html/design/get-started/ui-overview.jd
index 34cdd06..bfb9ec9 100644
--- a/docs/html/design/get-started/ui-overview.jd
+++ b/docs/html/design/get-started/ui-overview.jd
@@ -101,8 +101,7 @@
 
     <img src="{@docRoot}design/media/notifications_dismiss.png">
 
-<p>Most notifications have a one-line title and a one-line message. The recommended layout for a
-notification includes two lines. If necessary, you can add a third line. Timestamps are optional.</p>
+<p>Notifications can be expanded to uncover more details and relevant actions. When collapsed, notifications have a one-line title and a one-line message.The recommended layout for a notification includes two lines. If necessary, you can add a third line.</p>
 <p>Swiping a notification right or left removes it from the notification drawer.</p>
 
   </div>
diff --git a/docs/html/design/media/accessibility_contentdesc.png b/docs/html/design/media/accessibility_contentdesc.png
new file mode 100644
index 0000000..6515711
--- /dev/null
+++ b/docs/html/design/media/accessibility_contentdesc.png
Binary files differ
diff --git a/docs/html/design/media/action_bar_pattern_share_pack.png b/docs/html/design/media/action_bar_pattern_share_pack.png
index dde18f3..c8cff61 100644
--- a/docs/html/design/media/action_bar_pattern_share_pack.png
+++ b/docs/html/design/media/action_bar_pattern_share_pack.png
Binary files differ
diff --git a/docs/html/design/media/actionbar_drawer.png b/docs/html/design/media/actionbar_drawer.png
new file mode 100644
index 0000000..95e04f5
--- /dev/null
+++ b/docs/html/design/media/actionbar_drawer.png
Binary files differ
diff --git a/docs/html/design/media/app_structure_book_detail_page_flip.png b/docs/html/design/media/app_structure_book_detail_page_flip.png
index 0cca587..1066094 100644
--- a/docs/html/design/media/app_structure_book_detail_page_flip.png
+++ b/docs/html/design/media/app_structure_book_detail_page_flip.png
Binary files differ
diff --git a/docs/html/design/media/app_structure_gallery_filmstrip.png b/docs/html/design/media/app_structure_gallery_filmstrip.png
index 483bafa..a937533 100644
--- a/docs/html/design/media/app_structure_gallery_filmstrip.png
+++ b/docs/html/design/media/app_structure_gallery_filmstrip.png
Binary files differ
diff --git a/docs/html/design/media/building_blocks_landing.png b/docs/html/design/media/building_blocks_landing.png
index 2da47b7..40ab0da 100644
--- a/docs/html/design/media/building_blocks_landing.png
+++ b/docs/html/design/media/building_blocks_landing.png
Binary files differ
diff --git a/docs/html/design/media/color_spectrum.png b/docs/html/design/media/color_spectrum.png
index 7d2c023..b7ab309 100644
--- a/docs/html/design/media/color_spectrum.png
+++ b/docs/html/design/media/color_spectrum.png
Binary files differ
diff --git a/docs/html/design/media/compatibility_physical_buttons.png b/docs/html/design/media/compatibility_physical_buttons.png
index 30d5ddd..66a23c8 100644
--- a/docs/html/design/media/compatibility_physical_buttons.png
+++ b/docs/html/design/media/compatibility_physical_buttons.png
Binary files differ
diff --git a/docs/html/design/media/compatibility_virtual_nav.png b/docs/html/design/media/compatibility_virtual_nav.png
index ea595a4..27d39b2 100644
--- a/docs/html/design/media/compatibility_virtual_nav.png
+++ b/docs/html/design/media/compatibility_virtual_nav.png
Binary files differ
diff --git a/docs/html/design/media/confirm_ack_acknowledge.png b/docs/html/design/media/confirm_ack_acknowledge.png
new file mode 100644
index 0000000..b78eb14
--- /dev/null
+++ b/docs/html/design/media/confirm_ack_acknowledge.png
Binary files differ
diff --git a/docs/html/design/media/confirm_ack_confirming.png b/docs/html/design/media/confirm_ack_confirming.png
new file mode 100644
index 0000000..20a9c02
--- /dev/null
+++ b/docs/html/design/media/confirm_ack_confirming.png
Binary files differ
diff --git a/docs/html/design/media/confirm_ack_draft_deleted.png b/docs/html/design/media/confirm_ack_draft_deleted.png
new file mode 100644
index 0000000..f189db9
--- /dev/null
+++ b/docs/html/design/media/confirm_ack_draft_deleted.png
Binary files differ
diff --git a/docs/html/design/media/confirm_ack_ex_beam.png b/docs/html/design/media/confirm_ack_ex_beam.png
new file mode 100644
index 0000000..d099912
--- /dev/null
+++ b/docs/html/design/media/confirm_ack_ex_beam.png
Binary files differ
diff --git a/docs/html/design/media/confirm_ack_ex_books.png b/docs/html/design/media/confirm_ack_ex_books.png
new file mode 100644
index 0000000..634d7b9
--- /dev/null
+++ b/docs/html/design/media/confirm_ack_ex_books.png
Binary files differ
diff --git a/docs/html/design/media/confirm_ack_ex_draftsave.png b/docs/html/design/media/confirm_ack_ex_draftsave.png
new file mode 100644
index 0000000..473368d
--- /dev/null
+++ b/docs/html/design/media/confirm_ack_ex_draftsave.png
Binary files differ
diff --git a/docs/html/design/media/confirm_ack_ex_plus1.png b/docs/html/design/media/confirm_ack_ex_plus1.png
new file mode 100644
index 0000000..6de6710
--- /dev/null
+++ b/docs/html/design/media/confirm_ack_ex_plus1.png
Binary files differ
diff --git a/docs/html/design/media/confirm_ack_ex_removeapp.png b/docs/html/design/media/confirm_ack_ex_removeapp.png
new file mode 100644
index 0000000..0abacce
--- /dev/null
+++ b/docs/html/design/media/confirm_ack_ex_removeapp.png
Binary files differ
diff --git a/docs/html/design/media/confirm_ack_flowchart.png b/docs/html/design/media/confirm_ack_flowchart.png
new file mode 100644
index 0000000..3935d47
--- /dev/null
+++ b/docs/html/design/media/confirm_ack_flowchart.png
Binary files differ
diff --git a/docs/html/design/media/dialogs_popups_example.png b/docs/html/design/media/dialogs_popups_example.png
index 2deb00d..c7536f3 100644
--- a/docs/html/design/media/dialogs_popups_example.png
+++ b/docs/html/design/media/dialogs_popups_example.png
Binary files differ
diff --git a/docs/html/design/media/downloads_stencils.png b/docs/html/design/media/downloads_stencils.png
index 9e09319..9b1a9fe 100644
--- a/docs/html/design/media/downloads_stencils.png
+++ b/docs/html/design/media/downloads_stencils.png
Binary files differ
diff --git a/docs/html/design/media/extras_googleio_12.png b/docs/html/design/media/extras_googleio_12.png
new file mode 100644
index 0000000..7ab994d
--- /dev/null
+++ b/docs/html/design/media/extras_googleio_12.png
Binary files differ
diff --git a/docs/html/design/media/help_better.png b/docs/html/design/media/help_better.png
new file mode 100644
index 0000000..83d7b07
--- /dev/null
+++ b/docs/html/design/media/help_better.png
Binary files differ
diff --git a/docs/html/design/media/help_cling.png b/docs/html/design/media/help_cling.png
new file mode 100644
index 0000000..c91d189
--- /dev/null
+++ b/docs/html/design/media/help_cling.png
Binary files differ
diff --git a/docs/html/design/media/help_dont.png b/docs/html/design/media/help_dont.png
new file mode 100644
index 0000000..3c52c97
--- /dev/null
+++ b/docs/html/design/media/help_dont.png
Binary files differ
diff --git a/docs/html/design/media/help_evenbetter.png b/docs/html/design/media/help_evenbetter.png
new file mode 100644
index 0000000..66b9d162
--- /dev/null
+++ b/docs/html/design/media/help_evenbetter.png
Binary files differ
diff --git a/docs/html/design/media/help_overflow.png b/docs/html/design/media/help_overflow.png
new file mode 100644
index 0000000..fb2bc0a
--- /dev/null
+++ b/docs/html/design/media/help_overflow.png
Binary files differ
diff --git a/docs/html/design/media/help_solo_overflow.png b/docs/html/design/media/help_solo_overflow.png
new file mode 100644
index 0000000..9423ede
--- /dev/null
+++ b/docs/html/design/media/help_solo_overflow.png
Binary files differ
diff --git a/docs/html/design/media/iconography_notification_focal.png b/docs/html/design/media/iconography_notification_focal.png
index 20d5e8f..f21954f1 100644
--- a/docs/html/design/media/iconography_notification_focal.png
+++ b/docs/html/design/media/iconography_notification_focal.png
Binary files differ
diff --git a/docs/html/design/media/index_landing_page.png b/docs/html/design/media/index_landing_page.png
index 3f319b0..2065344 100644
--- a/docs/html/design/media/index_landing_page.png
+++ b/docs/html/design/media/index_landing_page.png
Binary files differ
diff --git a/docs/html/design/media/multipane_expand.png b/docs/html/design/media/multipane_expand.png
index f761e5f..6014cc8 100644
--- a/docs/html/design/media/multipane_expand.png
+++ b/docs/html/design/media/multipane_expand.png
Binary files differ
diff --git a/docs/html/design/media/multipane_show.png b/docs/html/design/media/multipane_show.png
index b10c91c..9993c9b 100644
--- a/docs/html/design/media/multipane_show.png
+++ b/docs/html/design/media/multipane_show.png
Binary files differ
diff --git a/docs/html/design/media/new_accessibility.png b/docs/html/design/media/new_accessibility.png
new file mode 100644
index 0000000..864ee5c
--- /dev/null
+++ b/docs/html/design/media/new_accessibility.png
Binary files differ
diff --git a/docs/html/design/media/new_notifications.png b/docs/html/design/media/new_notifications.png
new file mode 100644
index 0000000..a7293c8
--- /dev/null
+++ b/docs/html/design/media/new_notifications.png
Binary files differ
diff --git a/docs/html/design/media/new_widgets.png b/docs/html/design/media/new_widgets.png
new file mode 100644
index 0000000..7e6201b
--- /dev/null
+++ b/docs/html/design/media/new_widgets.png
Binary files differ
diff --git a/docs/html/design/media/notifications_dismiss.png b/docs/html/design/media/notifications_dismiss.png
index 71bed4f..696a97f 100644
--- a/docs/html/design/media/notifications_dismiss.png
+++ b/docs/html/design/media/notifications_dismiss.png
Binary files differ
diff --git a/docs/html/design/media/notifications_expand_contract_msg.png b/docs/html/design/media/notifications_expand_contract_msg.png
new file mode 100644
index 0000000..056c9f2
--- /dev/null
+++ b/docs/html/design/media/notifications_expand_contract_msg.png
Binary files differ
diff --git a/docs/html/design/media/notifications_pattern_additional_fail.png b/docs/html/design/media/notifications_pattern_additional_fail.png
index 707c98c..4f056db 100644
--- a/docs/html/design/media/notifications_pattern_additional_fail.png
+++ b/docs/html/design/media/notifications_pattern_additional_fail.png
Binary files differ
diff --git a/docs/html/design/media/notifications_pattern_additional_win.png b/docs/html/design/media/notifications_pattern_additional_win.png
index eb193d8..9d69dfd 100644
--- a/docs/html/design/media/notifications_pattern_additional_win.png
+++ b/docs/html/design/media/notifications_pattern_additional_win.png
Binary files differ
diff --git a/docs/html/design/media/notifications_pattern_anatomy.png b/docs/html/design/media/notifications_pattern_anatomy.png
index cacc183..c9fdf85 100644
--- a/docs/html/design/media/notifications_pattern_anatomy.png
+++ b/docs/html/design/media/notifications_pattern_anatomy.png
Binary files differ
diff --git a/docs/html/design/media/notifications_pattern_dialog_toast.png b/docs/html/design/media/notifications_pattern_dialog_toast.png
deleted file mode 100644
index 517d57b..0000000
--- a/docs/html/design/media/notifications_pattern_dialog_toast.png
+++ /dev/null
Binary files differ
diff --git a/docs/html/design/media/notifications_pattern_expand_contract.png b/docs/html/design/media/notifications_pattern_expand_contract.png
new file mode 100644
index 0000000..e89835c
--- /dev/null
+++ b/docs/html/design/media/notifications_pattern_expand_contract.png
Binary files differ
diff --git a/docs/html/design/media/notifications_pattern_expandable.png b/docs/html/design/media/notifications_pattern_expandable.png
new file mode 100644
index 0000000..31cb3f1
--- /dev/null
+++ b/docs/html/design/media/notifications_pattern_expandable.png
Binary files differ
diff --git a/docs/html/design/media/notifications_pattern_ongoing_music.png b/docs/html/design/media/notifications_pattern_ongoing_music.png
index 01039bd..77b24ed 100644
--- a/docs/html/design/media/notifications_pattern_ongoing_music.png
+++ b/docs/html/design/media/notifications_pattern_ongoing_music.png
Binary files differ
diff --git a/docs/html/design/media/notifications_pattern_personal.png b/docs/html/design/media/notifications_pattern_personal.png
new file mode 100644
index 0000000..a7293c8
--- /dev/null
+++ b/docs/html/design/media/notifications_pattern_personal.png
Binary files differ
diff --git a/docs/html/design/media/notifications_pattern_phone_icons.png b/docs/html/design/media/notifications_pattern_phone_icons.png
index 09d8a83..bee66c9 100644
--- a/docs/html/design/media/notifications_pattern_phone_icons.png
+++ b/docs/html/design/media/notifications_pattern_phone_icons.png
Binary files differ
diff --git a/docs/html/design/media/notifications_pattern_priority.png b/docs/html/design/media/notifications_pattern_priority.png
new file mode 100644
index 0000000..e89835c
--- /dev/null
+++ b/docs/html/design/media/notifications_pattern_priority.png
Binary files differ
diff --git a/docs/html/design/media/notifications_pattern_real_time_people.png b/docs/html/design/media/notifications_pattern_real_time_people.png
index 2af40b8..d03b6f0 100644
--- a/docs/html/design/media/notifications_pattern_real_time_people.png
+++ b/docs/html/design/media/notifications_pattern_real_time_people.png
Binary files differ
diff --git a/docs/html/design/media/notifications_pattern_social_fail.png b/docs/html/design/media/notifications_pattern_social_fail.png
index 2c8fddc..aa0e028 100644
--- a/docs/html/design/media/notifications_pattern_social_fail.png
+++ b/docs/html/design/media/notifications_pattern_social_fail.png
Binary files differ
diff --git a/docs/html/design/media/notifications_pattern_two_actions.png b/docs/html/design/media/notifications_pattern_two_actions.png
new file mode 100644
index 0000000..7c19f2e
--- /dev/null
+++ b/docs/html/design/media/notifications_pattern_two_actions.png
Binary files differ
diff --git a/docs/html/design/media/principles_decide_for_me.png b/docs/html/design/media/principles_decide_for_me.png
index 2d8b883..8080b4e 100644
--- a/docs/html/design/media/principles_decide_for_me.png
+++ b/docs/html/design/media/principles_decide_for_me.png
Binary files differ
diff --git a/docs/html/design/media/principles_error.png b/docs/html/design/media/principles_error.png
index 93767660..c867fe6 100644
--- a/docs/html/design/media/principles_error.png
+++ b/docs/html/design/media/principles_error.png
Binary files differ
diff --git a/docs/html/design/media/principles_information_when_need_it.png b/docs/html/design/media/principles_information_when_need_it.png
index c5ef3ca..d78d5c5 100644
--- a/docs/html/design/media/principles_information_when_need_it.png
+++ b/docs/html/design/media/principles_information_when_need_it.png
Binary files differ
diff --git a/docs/html/design/media/principles_keep_it_brief.png b/docs/html/design/media/principles_keep_it_brief.png
index 9c2813b..ee7dbbb 100644
--- a/docs/html/design/media/principles_keep_it_brief.png
+++ b/docs/html/design/media/principles_keep_it_brief.png
Binary files differ
diff --git a/docs/html/design/media/principles_never_lose_stuff.png b/docs/html/design/media/principles_never_lose_stuff.png
index acbefea..84037d9 100644
--- a/docs/html/design/media/principles_never_lose_stuff.png
+++ b/docs/html/design/media/principles_never_lose_stuff.png
Binary files differ
diff --git a/docs/html/design/media/progress_activity_custom.png b/docs/html/design/media/progress_activity_custom.png
new file mode 100644
index 0000000..2bfdd52
--- /dev/null
+++ b/docs/html/design/media/progress_activity_custom.png
Binary files differ
diff --git a/docs/html/design/media/progress_activity_custom_app.png b/docs/html/design/media/progress_activity_custom_app.png
new file mode 100644
index 0000000..e572508
--- /dev/null
+++ b/docs/html/design/media/progress_activity_custom_app.png
Binary files differ
diff --git a/docs/html/design/media/progress_activity_do.png b/docs/html/design/media/progress_activity_do.png
new file mode 100644
index 0000000..fd22436
--- /dev/null
+++ b/docs/html/design/media/progress_activity_do.png
Binary files differ
diff --git a/docs/html/design/media/progress_activity_dont.png b/docs/html/design/media/progress_activity_dont.png
new file mode 100644
index 0000000..08c4b5d
--- /dev/null
+++ b/docs/html/design/media/progress_activity_dont.png
Binary files differ
diff --git a/docs/html/design/media/swipe_views2.png b/docs/html/design/media/swipe_views2.png
index 6479a2f..ee0f2c4 100644
--- a/docs/html/design/media/swipe_views2.png
+++ b/docs/html/design/media/swipe_views2.png
Binary files differ
diff --git a/docs/html/design/media/swipe_views3.png b/docs/html/design/media/swipe_views3.png
new file mode 100644
index 0000000..bdf9994
--- /dev/null
+++ b/docs/html/design/media/swipe_views3.png
Binary files differ
diff --git a/docs/html/design/media/tabs_youtube.png b/docs/html/design/media/tabs_youtube.png
index 69e9268..4ea6c1c 100644
--- a/docs/html/design/media/tabs_youtube.png
+++ b/docs/html/design/media/tabs_youtube.png
Binary files differ
diff --git a/docs/html/design/media/themes_holo_dark.png b/docs/html/design/media/themes_holo_dark.png
index 0a5876a..e1f4477 100644
--- a/docs/html/design/media/themes_holo_dark.png
+++ b/docs/html/design/media/themes_holo_dark.png
Binary files differ
diff --git a/docs/html/design/media/themes_holo_inverse.png b/docs/html/design/media/themes_holo_inverse.png
index 50be4fb..528d119 100644
--- a/docs/html/design/media/themes_holo_inverse.png
+++ b/docs/html/design/media/themes_holo_inverse.png
Binary files differ
diff --git a/docs/html/design/media/themes_holo_light.png b/docs/html/design/media/themes_holo_light.png
index edc7f77..4f34bb3 100644
--- a/docs/html/design/media/themes_holo_light.png
+++ b/docs/html/design/media/themes_holo_light.png
Binary files differ
diff --git a/docs/html/design/media/ui_overview_notifications.png b/docs/html/design/media/ui_overview_notifications.png
index bc0513f..fe4375e 100644
--- a/docs/html/design/media/ui_overview_notifications.png
+++ b/docs/html/design/media/ui_overview_notifications.png
Binary files differ
diff --git a/docs/html/design/media/widgets_collection_bookmarks.png b/docs/html/design/media/widgets_collection_bookmarks.png
new file mode 100644
index 0000000..86d4d88
--- /dev/null
+++ b/docs/html/design/media/widgets_collection_bookmarks.png
Binary files differ
diff --git a/docs/html/design/media/widgets_collection_gmail.png b/docs/html/design/media/widgets_collection_gmail.png
new file mode 100644
index 0000000..bbd538d
--- /dev/null
+++ b/docs/html/design/media/widgets_collection_gmail.png
Binary files differ
diff --git a/docs/html/design/media/widgets_config.png b/docs/html/design/media/widgets_config.png
new file mode 100644
index 0000000..0ac3473
--- /dev/null
+++ b/docs/html/design/media/widgets_config.png
Binary files differ
diff --git a/docs/html/design/media/widgets_control.png b/docs/html/design/media/widgets_control.png
new file mode 100644
index 0000000..a46add8
--- /dev/null
+++ b/docs/html/design/media/widgets_control.png
Binary files differ
diff --git a/docs/html/design/media/widgets_gestures.png b/docs/html/design/media/widgets_gestures.png
new file mode 100644
index 0000000..f991609
--- /dev/null
+++ b/docs/html/design/media/widgets_gestures.png
Binary files differ
diff --git a/docs/html/design/media/widgets_hybrid.png b/docs/html/design/media/widgets_hybrid.png
new file mode 100644
index 0000000..470f75f
--- /dev/null
+++ b/docs/html/design/media/widgets_hybrid.png
Binary files differ
diff --git a/docs/html/design/media/widgets_info.png b/docs/html/design/media/widgets_info.png
new file mode 100644
index 0000000..6621158
--- /dev/null
+++ b/docs/html/design/media/widgets_info.png
Binary files differ
diff --git a/docs/html/design/media/widgets_resizing01.png b/docs/html/design/media/widgets_resizing01.png
new file mode 100644
index 0000000..5c85df6
--- /dev/null
+++ b/docs/html/design/media/widgets_resizing01.png
Binary files differ
diff --git a/docs/html/design/media/widgets_resizing02.png b/docs/html/design/media/widgets_resizing02.png
new file mode 100644
index 0000000..28f9461
--- /dev/null
+++ b/docs/html/design/media/widgets_resizing02.png
Binary files differ
diff --git a/docs/html/design/patterns/accessibility.jd b/docs/html/design/patterns/accessibility.jd
new file mode 100644
index 0000000..b2fbda9
--- /dev/null
+++ b/docs/html/design/patterns/accessibility.jd
@@ -0,0 +1,80 @@
+page.title=Accessibility
+@jd:body
+
+<p>One of Android's missions is to organize the world's information and make it universally accessible and useful. Accessibility is the measure of how successfully a product can be used by people with varying abilities. Our mission applies to all users-including people with disabilities such as visual impairment, color deficiency, hearing loss, and limited dexterity.</p>
+<p><a href="https://www.google.com/#hl=en&q=universal+design&fp=1">Universal design</a> is the practice of making products that are inherently accessible to all users, regardless of ability. The Android design patterns were created in accordance with universal design principles, and following them will help your app meet basic usability standards. Adhering to universal design and enabling Android's accessibility tools will make your app as accessible as possible.</p>
+<p>Robust support for accessibility will increase your app's user base. It may also be required for adoption by some organizations.</p>
+<p><a href="http://www.google.com/accessibility/">Learn more about Google and accessibility.</a></p>
+
+<h2 id="tools">Android's Accessibility Tools</h2>
+<p>Android includes several features that support access for users with visual impairments; they don't require drastic visual changes to your app.</p>
+
+<ul>
+  <li><strong><a href="https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback">TalkBack</a></strong> is a pre-installed screen reader service provided by Google. It uses spoken feedback to describe the results of actions such as launching an app, and events such as notifications.</li>
+  <li><strong>Explore by Touch</strong> is a system feature that works with TalkBack, allowing you to touch your device's screen and hear what's under your finger via spoken feedback. This feature is helpful to users with low vision.</li>
+  <li><strong>Accessibility settings</strong> let you modify your device's display and sound options, such as increasing the text size, changing the speed at which text is spoken, and more.</li>
+</ul>
+
+<p>Some users use hardware or software directional controllers (such as a D-pad, trackball, keyboard) to jump from selection to selection on a screen. They interact with the structure of your app in a linear fashion, similar to 4-way remote control navigation on a television.</p>
+
+<h2 id="tools">Guidelines</h2>
+<p>The Android design principle "I should always know where I am" is key for accessibility concerns. As a user navigates through an application, they need feedback and a mental model of where they are. All users benefit from a strong sense of information hierarchy and an architecture that makes sense. Most users benefit from visual and haptic feedback during their navigation (such as labels, colors, icons, touch feedback) Low vision users benefit from explicit verbal descriptions and large visuals with high contrast.</p>
+<p>As you design your app, think about the labels and notations needed to navigate your app by sound. When using Explore by Touch, the user enables an invisible but audible layer of structure in your application. Like any other aspect of app design, this structure can be simple, elegant, and robust. The following are Android's recommended guidelines to enable effective navigation for all users.</p>
+
+<h4>Make navigation intuitive</h4>
+<p>Design well-defined, clear task flows with minimal navigation steps, especially for major user tasks. Make sure those tasks are navigable via focus controls. </p>
+
+<h4>Use recommended touch target sizes</h4>
+<p>48 dp is the recommended touch target size for on screen elements. Read about <a href="{@docRoot}design/style/metrics-grids.html">Android Metrics and Grids</a> to learn about implementation strategies to help most of your users. For certain users, it may be appropriate to use larger touch targets. An example of this is educational apps, where buttons larger than the minimum recommendations are appropriate for children with developing motor skills and people with manual dexterity challenges.</p>
+
+
+<h4>Label visual UI elements meaningfully</h4>
+<p>In your wireframes, <a href="{@docRoot}guide/topics/ui/accessibility/apps.html#label-ui">label functional UI components</a> that have no visible text. Those components might be buttons, icons, tabs with icons, and icons with state (like stars). Developers can use the <code><a href="{@docRoot}guide/topics/ui/accessibility/apps.html#label-ui">contentDescription</a></code> attribute to set the label.</p>
+
+<div class ="layout-content-row">
+    <div class="layout-content-col span-8">
+      <img src="{@docRoot}design/media/accessibility_contentdesc.png">
+    </div>
+    <div class="layout-content-col span-5 with-callouts">
+      <ol>
+        <li class="value-1">group</li>
+        <li class="value-2">all contacts</li>
+        <li class="value-3">favorites</li>
+        <li class="value-4">search</li>
+        <li class="value-5">action overflow button</li>
+        <li class="value-6">
+          <em>when starred:</em> remove from favorites </br>
+          <em>when not starred:</em> add to favorties</li>
+        <li class="value-7">action overflow button</li>
+        <li class="value-8">text message</li>
+        <li class="value-9">video chat</li>
+      </ol>
+  </div>
+</div>
+
+<h4>Provide alternatives to affordances that time out</h4>
+<p>Your app may have icons or controls that disappear after a certain amount of time. For example, five seconds after starting a video, playback controls may fade from the screen.</p>
+
+<p>Due to the way that TalkBack works, those controls are not read out loud unless they are focused on. If they fade out from the screen quickly, your user may not even be aware that they are available. Therefore, make sure that you are not relying on timed out controls for high priority task flows. (This is a good universal design guideline too.) If the controls enable an important function, make sure that the user can turn on the controls again and/or their function is duplicated elsewhere. You can also change the behavior of your app when accessibility services are turned on. Your developer may be able to make sure that timed-out controls won't disappear.</p>
+
+<h4>Use standard framework controls or enable TalkBack for custom controls</h4>
+<p>Standard Android framework controls work automatically with accessibility services and have ContentDescriptions built in by default.</p>
+
+<p>An oft-overlooked system control is font size. Users can turn on a system-wide large font size in Settings; using the default system font size in your application will enable the user's preferences in your app as well. To enable system font size in your app, mark text and their associated containers to be measured in <a href="{@docRoot}guide/practices/screens_support.html#screen-independence">scale pixels</a>.</p>
+
+<p>Also, keep in mind that when users have large fonts enabled or speak a different language than you, their type might be larger than the space you've allotted for it. Read <a href="{@docRoot}design/style/devices-displays.html">Devices and Displays</a> and <a href="http://developer.android.com/guide/practices/screens_support.html">Supporting Multiple Screens</a> for design strategies.</p>
+
+<p>If you use custom controls, Android has the developer tools in place to allow adherence to the above guidelines and provide meaningful descriptions about the UI. Provide adequate notation on your wireframes and direct your developer to the <a href="{@docRoot}guide/topics/ui/accessibility/apps.html#custom-views">Custom Views</a> documentation.</p>
+
+<h4>Try it out yourself</h4>
+<p>Turn on the TalkBack service in <strong>Settings > Accessibility</strong> and navigate your application using directional controls or eyes-free navigation.</p>
+
+<h2>Checklist</h2>
+<ul>
+  <li>Make navigation intuitive</li>
+  <li>Use recommended touch target sizes</li>
+  <li>Label visual UI elements meaningfully</li>
+  <li>Provide alternatives to affordances that time out</li>
+  <li>Use standard framework controls or enable TalkBack for custom controls</li>
+  <li>Try it out yourself</li>
+</ul>
\ No newline at end of file
diff --git a/docs/html/design/patterns/actionbar.jd b/docs/html/design/patterns/actionbar.jd
index 4206301..ba5b400 100644
--- a/docs/html/design/patterns/actionbar.jd
+++ b/docs/html/design/patterns/actionbar.jd
@@ -3,20 +3,15 @@
 
 <img src="{@docRoot}design/media/action_bar_pattern_overview.png">
 
-<p>The <em>action bar</em> is arguably the most important structural element of an Android app. It's a
-dedicated piece of real estate at the top of each screen that is generally persistent throughout the
-app.</p>
-<p><strong>The main purpose of the action bar is to</strong>:</p>
+<p>The <em>action bar</em> is a dedicated piece of real estate at the top of each screen that is generally persistent throughout the app.</p>
+<p><strong>It provides several key functions</strong>:</p>
 <ul>
-<li>Make important actions (such as <em>New</em> or <em>Search</em>, etc) prominent and accessible in a predictable
-   way.</li>
-<li>Support consistent navigation and view switching within apps.</li>
-<li>Reduce clutter by providing an action overflow for rarely used actions.</li>
-<li>Provide a dedicated space for giving your app an identity.</li>
+  <li>Makes important actions prominent and accessible in a predictable way (such as <em>New</em> or <em>Search</em>).</li>
+  <li>Supports consistent navigation and view switching within apps.</li>
+  <li>Reduces clutter by providing an action overflow for rarely used actions.</li>
+  <li>Provides a dedicated space for giving your app an identity.</li>
 </ul>
-<p>If you're new to writing Android apps, note that the action bar is one of the most important design
-elements you can implement. Following the guidelines described here will go a long way toward making
-your app's interface consistent with the core Android apps.</p>
+<p>If you're new to writing Android apps, note that the action bar is one of the most important design elements you can implement. Following the guidelines described here will go a long way toward making your app's interface consistent with the core Android apps.</p>
 <h2 id="organization">General Organization</h2>
 
 <p>The action bar is split into four different functional areas that apply to most apps.</p>
@@ -66,7 +61,7 @@
         <p>
 
 Show the most important actions of your app in the actions section. Actions that don't fit in the
-action bar are moved automatically to the action overflow.
+action bar are moved automatically to the action overflow. Long-press on an icon to view the action's name.
 
         </p>
       </li>
@@ -144,28 +139,44 @@
 <p>For more information, refer to the <a href="{@docRoot}design/patterns/selection.html">Selection
 pattern</a>.</p>
 
-<h2 id="elements">Action Bar Elements</h2>
+<h2 id="elements">View Controls</h2>
+<p>If your app displays data in different views, the action bar has three different controls to allow users to switch between them: tabs, spinners, and drawers.</p>
 
 <h4>Tabs</h4>
-<p><em>Tabs</em> display app views concurrently and make it easy to explore and switch between them. Use tabs
-if you expect your users to switch views frequently.</p>
+<p><em>Tabs</em> display app views concurrently and make it easy to explore and switch between them. Tabs may be fixed, where all tabs are simultaneously displayed, or may scroll, allowing a larger number of views to be presented.</p>
 
 <img src="{@docRoot}design/media/tabs_youtube.png">
 
-<p>There are two types of tabs: fixed and scrollable.</p>
+<p><strong>Use tabs if</strong>:</p>
+<ul>
+<li>You expect your app's users to switch views frequently.</li>
+<li>You want the user to be highly aware of the alternate views.</li>
+</ul>
 
+<h4>Fixed tabs</h4>
 <div class="layout-content-row">
   <div class="layout-content-col span-6">
+<p><em>Fixed tabs</em> are always visible on the screen, and can't be moved out of the way like scrollable
+tabs. Fixed tabs in the main action bar can move to the top bar when the screen orientation changes.</p>
+
+<p>Use fixed tabs to support quick changes between two or three app views. Fixed tabs should always allow the user to navigate between the views by swiping left or right on the content area.</p>
+
+  </div>
+  <div class="layout-content-col span-7">
+
+    <img src="{@docRoot}design/media/action_bar_pattern_default_tabs.png">
+    <div class="figure-caption">
+      Default fixed tabs shown in Holo Dark &amp; Light.
+    </div>
+
+  </div>
+</div>
 
 <h4>Scrollable tabs</h4>
-<p><em>Scrollable tabs</em> always take up the entire width of the bar, with the currently active view item in
-the center, and therefore need to live in a dedicated bar. Scrollable tabs can themselves be
-scrolled horizontally to bring more tabs into view.</p>
-<p>Use scrollable tabs if you have a large number of views or if you're unsure how many views will be
-displayed because your app inserts views dynamically (for example, open chats in a messaging app
-that the user can navigate between). Scrollable tabs should always allow the user to navigate
-between the views by swiping left or right on the content area as well as swiping the tabs
-themselves.</p>
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+<p><em>Scrollable tabs</em> always take up the entire width of the bar, with the currently active view item in the center, and therefore need to live in a dedicated bar. Scrollable tabs can themselves be scrolled horizontally to bring more tabs into view.</p>
+<p>Use scrollable tabs if you have a large number of views or if you're unsure how many views will be displayed because your app inserts views dynamically (for example, open chats in a messaging app that the user can navigate between). Scrollable tabs should always allow the user to navigate between the views by swiping left or right on the content area as well as swiping the tabs themselves.</p>
 
   </div>
   <div class="layout-content-col span-7">
@@ -186,30 +197,12 @@
 <div class="layout-content-row">
   <div class="layout-content-col span-6">
 
-<h4>Fixed tabs</h4>
-<p><em>Fixed tabs</em> are always visible on the screen, and can't be moved out of the way like scrollable
-tabs. Fixed tabs in the main action bar can move to the top bar when the screen orientation changes.</p>
-
-  </div>
-  <div class="layout-content-col span-7">
-
-    <img src="{@docRoot}design/media/action_bar_pattern_default_tabs.png">
-    <div class="figure-caption">
-      Default fixed tabs shown in Holo Dark &amp; Light.
-    </div>
-
-  </div>
-</div>
-
-<div class="layout-content-row">
-  <div class="layout-content-col span-6">
-
 <h4>Spinners</h4>
 <p>A <em>spinner</em> is a drop-down menu that allows users to switch between views of your app. </p>
-<p><strong>Use spinners rather than tabs in the main action bar if</strong>:</p>
+<p><strong>Use a spinner in the main action bar if</strong>:</p>
 <ul>
 <li>You don't want to give up the vertical screen real estate for a dedicated tab bar.</li>
-<li>You expect your app's users to switch views infrequently.</li>
+<li>The user is switching between views of the same data set (for example: calendar events viewed by day, week, or month) or data sets of the same type (such as content for two different accounts).</li>
 </ul>
 
   </div>
@@ -223,7 +216,24 @@
   </div>
 </div>
 
-<h4>Action buttons</h4>
+<h4>Drawers</h4>
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+<p>A <em>drawer</em> is a slide-out menu that allows users to switch between views of your app. It can be opened by touching the action bar's app icon (decorated with the Up caret.) Additionally, a drawer can be revealed by an edge swipe from the left of the screen, and dismissed by swiping from the right edge of the drawer. However, because many users will rely on Up navigation to open a drawer, it is only suitable for use at the topmost level of your app's hierarchy.</p>
+
+<p><strong>Open a drawer from the main action bar if</strong>:</p>
+<ul>
+<li>You don't want to give up the vertical screen real estate for a dedicated tab bar.</li>
+<li>You want to provide direct navigation to a number of views within your app which don't have direct relationships between each other.</li>
+</ul>
+
+  </div>
+  <div class="layout-content-col span-7">
+    <img src="{@docRoot}design/media/actionbar_drawer.png">
+  </div>
+</div>
+
+<h2>Action buttons</h2>
 <p><em>Action buttons</em> on the action bar surface your app's most important activities. Think about which
 buttons will get used most often, and order them accordingly. Depending on available screen real
 estate, the system shows your most important actions as action buttons and moves the rest to the
@@ -283,7 +293,7 @@
 </p>
 <p>
 
-<a href="https://dl-ssl.google.com/android/design/Android_Design_Icons_20120229.zip">Download the Action Bar Icon Pack</a>
+<a href="{@docRoot}downloads/design/Android_Design_Icons_20120229.zip">Download the Action Bar Icon Pack</a>
 
 </p>
 
diff --git a/docs/html/design/patterns/app-structure.jd b/docs/html/design/patterns/app-structure.jd
index e2398ed..a483522 100644
--- a/docs/html/design/patterns/app-structure.jd
+++ b/docs/html/design/patterns/app-structure.jd
@@ -185,28 +185,18 @@
 in a category view.</p>
 <h2 id="details">Details</h2>
 
-<p>The detail view allows you to view and act on your data. The layout of the detail view depends on
-the data type being displayed, and therefore differs widely among apps.</p>
+<p>The detail view allows you to view and act on your data. The layout of the detail view depends on the data type being displayed, and therefore differs widely among apps.</p>
 
 <div class="layout-content-row">
   <div class="layout-content-col span-4">
 
 <h4>Layout</h4>
-<p>Consider the activities people will perform in the detail view and arrange the layout accordingly.
-For immersive content, make use of the lights-out mode to allow for distraction-free viewing of
-full-screen content.</p>
-
-    <img src="{@docRoot}design/media/app_structure_people_detail.png">
+<p>Consider the activities people will perform in the detail view and arrange the layout accordingly.</p>
 
   </div>
   <div class="layout-content-col span-9">
 
-    <img src="{@docRoot}design/media/app_structure_book_detail_page_flip.png">
-    <div class="figure-caption">
-      Google Books' detail view is all about replicating the experience of reading an actual book.
-      The page-flip animation reinforces that notion. To create an immersive experience the app
-      enters lights-out mode, which hides all system UI affordances.
-    </div>
+    <img src="{@docRoot}design/media/app_structure_people_detail.png">
 
     <div class="figure-caption">
       The purpose of the People app's detail view is to surface communication options. The list view
@@ -217,9 +207,25 @@
   </div>
 </div>
 
+<div class="layout-content-row">
+  <div class="layout-content-col span-4">
+
+<h4>Lights-out mode</h4>
+<p>Immersive content like media and games is best experienced full screen without distractions. But that doesn't mean you can't also offer actions on the content like sharing, commenting, or searching. If the user hasn't interacted with any of the controls after a short period of time, automatically fade away the action bar and all system UI affordances so the user can lean back and enjoy the content. We call this lights-out mode. Later, if the user wants to take some action, they can touch anywhere on the screen to exit lights-out mode and bring back the controls.</p>
+
+  </div>
+  <div class="layout-content-col span-9">
+
+    <img src="{@docRoot}design/media/app_structure_book_detail_page_flip.png">
+    <div class="figure-caption">
+      Google Books' detail view replicates the immersive experience of reading an actual book through lights-out mode and a page-flip animation.
+    </div>
+  </div>
+</div>
+
 <h4>Make navigation between detail views efficient</h4>
 <p>If your users are likely to want to look at multiple items in sequence, allow them to navigate
-between items from within the detail view. Use swipe views or other techniques, such as filmstrips,
+between items from within the detail view. Use swipe views or other techniques, such as thumbnail view controls,
 to achieve this.</p>
 
 <img src="{@docRoot}design/media/app_structure_gmail_swipe.png">
@@ -229,8 +235,8 @@
 
 <img src="{@docRoot}design/media/app_structure_gallery_filmstrip.png">
 <div class="figure-caption">
-  In addition to supporting swipe gestures to move left or right through images, Gallery provides a
-  filmstrip control that lets people quickly jump to specific images.
+  In addition to supporting swipe gestures to move left or right through pages, Magazines provides a
+  thumbnail view control that lets people quickly jump to specific pages.
 </div>
 
 <h2 id="checklist">Checklist</h2>
diff --git a/docs/html/design/patterns/confirming-acknowledging.jd b/docs/html/design/patterns/confirming-acknowledging.jd
new file mode 100644
index 0000000..ce0631b
--- /dev/null
+++ b/docs/html/design/patterns/confirming-acknowledging.jd
@@ -0,0 +1,69 @@
+page.title=Confirming &amp; Acknowledging
+@jd:body
+
+<p>In some situations, when a user invokes an action in your app, it's a good idea to <em>confirm</em> or <em>acknowledge</em> that action through text.</p>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+    <img src="{@docRoot}design/media/confirm_ack_confirming.png">
+    <p><strong>Confirming</strong> is asking the user to verify that they truly want to proceed with an action they just invoked. In some cases, the confirmation is presented along with a warning or critical information related to the action that they need to consider.</p>
+  </div>
+  <div class="layout-content-col span-6">
+    <img src="{@docRoot}design/media/confirm_ack_acknowledge.png">
+    <p><strong>Acknowledging</strong> is displaying text to let the user know that the action they just invoked has been completed. This removes uncertainty about implicit operations that the system is taking. In some cases, the acknowledgment is presented along with an option to undo the action.</p>
+  </div>
+</div>
+
+<p>Communicating to users in these ways can help alleviate uncertainty about things that have happened or will happen. Confirming or acknowledging can also prevent users from making mistakes they might regret.</p>
+
+<h2>When to Confirm or Acknowledge User Actions</h2>
+<p>Not all actions warrant a confirmation or an acknowledgment. Use this flowchart to guide your design decisions.</p>
+<img src="{@docRoot}design/media/confirm_ack_flowchart.png">
+
+<h2>Confirming</h2>
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+    <h4>Example: Google Play Books</h4>
+    <img src="{@docRoot}design/media/confirm_ack_ex_books.png">
+    <p>In this example, the user has requested to delete a book from their Google Play library. An <a href="{@docRoot}design/building-blocks/dialogs.html#alerts">alert</a> appears to confirm this action because it's important to understand that the book will no longer be available from any device.</p>
+    <p>When crafting a confirmation dialog, make the title meaningful by echoing the requested action.</p>
+  </div>
+  <div class="layout-content-col span-7">
+    <h4>Example: Android Beam</h4>
+    <img src="{@docRoot}design/media/confirm_ack_ex_beam.png">
+    <p>Confirmations don't necessarily have to be presented in an alert with two buttons. After initiating Android Beam, the user is prompted to touch the content to be shared (in this example, it's a photo). If they decide not to proceed, they simply move their phone away.</p>
+  </div>
+</div>
+
+<h2>Acknowledging</h2>
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+    <h4>Example: Abandoned Gmail draft saved</h4>
+    <img src="{@docRoot}design/media/confirm_ack_ex_draftsave.png">
+    <p>In this example, if the user navigates back or up from the Gmail compose screen, something possibly unexpected happens: the current draft is automatically saved. An acknowledgment in the form of a toast makes that apparent. It fades after a few seconds.</p>
+    <p>Undo isn't appropriate here because saving was initiated by the app, not the user. And it's quick and easy to resume composing the message by navigating to the list of drafts.</p>
+
+  </div>
+  <div class="layout-content-col span-6">
+    <h4>Example: Gmail conversation deleted</h4>
+    <img src="{@docRoot}design/media/confirm_ack_draft_deleted.png">
+    <p>After the user deletes a conversation from the list in Gmail, an acknowledgment appears with an undo option. The acknowledgment remains until the user takes an unrelated action, such as scrolling the list.</p>
+  </div>
+</div>
+
+<h2>No Confirmation or Acknowledgment</h2>
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+    <h4>Example: +1'ing</h4>
+    <img style="padding: 33px 0 30px;" src="{@docRoot}design/media/confirm_ack_ex_plus1.png">
+    <p><strong>Confirmation is unnecessary</strong>. If the user +1'd by accident, it's not a big deal. They can just touch the button again to undo the action.</p>
+    <p><strong>Acknowledgment is unnecessary</strong>. The user will see the +1 button bounce and turn red. That's a very clear signal.</p>
+  </div>
+  <div class="layout-content-col span-7">
+    <h4>Example: Removing an app from the Home Screen</h4>
+    <img src="{@docRoot}design/media/confirm_ack_ex_removeapp.png">
+    <p><strong>Confirmation is unnecessary</strong>. This is a deliberate action: the user must drag and drop an item onto a relatively large and isolated target. Therefore, accidents are highly unlikely. But if the user regrets the decision, it only takes a few seconds to bring it back again.</p>
+    <p><strong>Acknowledgment is unnecessary</strong>. The user will know the app is gone from the Home Screen because they made it disappear by dragging it away.</p>
+
+  </div>
+</div>
\ No newline at end of file
diff --git a/docs/html/design/patterns/help.jd b/docs/html/design/patterns/help.jd
new file mode 100644
index 0000000..cdac54d
--- /dev/null
+++ b/docs/html/design/patterns/help.jd
@@ -0,0 +1,112 @@
+page.title=Help
+@jd:body
+
+<p>We wish we could guarantee that if you follow every piece of advice on this website, everyone will be able to learn and use your app without a hitch. Sadly, that's not the case.</p>
+
+<p>Some of your users will run into questions or problems along the way. They'll be looking for answers <strong>within your app</strong>, and if they don't find them quickly, they may leave and never come back.</p>
+
+<p>This page covers design patterns for making help accessible in your app and tips for creating help content for users who are eager for assistance.</p>
+
+<h2 id="your-app">Designing Help into Your App</h2>
+
+<h3>Don't show unsolicited help, except in very limited cases</h3>
+<p>Naturally, you want everyone to quickly learn the ropes, discover the cool features, and get the most out of your app. So you might be tempted to present a one-time introductory slideshow, video, or splash screen to all new users when they first open the app. Or you might be drawn to the idea of displaying helpful text bubbles or dialogs when users interact with certain features for the first time.</p>
+<p>In almost all cases, we advise <strong>against</strong> approaches like these because:</p>
+<ul>
+  <li><strong>They're interruptions.</strong> People will be eager to start using your app, and anything you put in front of them will feel like an obstacle or possibly an annoyance, despite your good intentions. And because they didn't ask for it, they probably won't pay close attention to it.</li>
+  <li><strong>They're usually not necessary.</strong> If you have usability concerns about an aspect of your app, don't just throw help at the problem. Try to solve it in the UI. Apply Android design patterns, styles, and building blocks, and you'll go a long way in reducing the need to educate your users.</li>
+</ul>
+<p>The only reason for showing pure help content to new users unsolicited is:<br>
+<em>To teach high value functionality that's only available through a gesture.</em></p>
+
+<p>For example, we use help content to teach users how to place apps on their Home Screen. This functionality is:</p>
+<div class="layout-content-row">
+  <div class="layout-content-col span-8">
+    <ul>
+      <li><strong>High value</strong>
+      <p style="margin-top:0;">Without it, users wouldn't be able to customize the most frequently visited Android screen to meet their needs.</p></li>
+      <li><strong>Available only through a gesture</strong>
+      <p style="margin-top:0;">Because there's no button or menu for it, users might not ever discover it on their own.</p></li>
+    </ul>
+    <p>However, not all high value gesture-only functionality needs a tutorial. For example, don't teach users how to scroll content. They already know how because it's a fundamental, system-wide interaction.</p>
+  </div>
+  <div class="layout-content-col span-5">
+    <img src="{@docRoot}design/media/help_cling.png">
+    <div class="figure-caption">
+      The first time each user visits the All Apps screen, a semi-transparent overlay appears to teach an important gesture.
+    </div>
+  </div>
+  <p class="clearfix">Bottom line: when it comes to offering help in your app, it's much better to <strong>let users come to you</strong> when they need it.</p>
+</div>
+
+<h3 id="standard-design">Follow the standard design for navigating to help</h3>
+
+<p>On every screen in your app, offer help in the <a href="{@docRoot}design/patterns/actionbar.html">action overflow</a>. Always make it the very last item in the menu and label it "Help".</p>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-7">
+    <img src="{@docRoot}design/media/help_overflow.png">
+  </div>
+  <div class="layout-content-col span-6">
+    <img src="{@docRoot}design/media/help_solo_overflow.png">
+    <div class="figure-caption">
+      Even if your screen has no other action overflow items, "Help" should appear there and not be promoted to the action bar.
+    </div>
+  </div>
+  <p>We've established this standard design so that when users are desperate for help, they won't have to hunt to find it (see design principle: <a href="{@docRoot}design/get-started/principles.html#give-me-tricks">Give me tricks that work everywhere</a>).</p>
+</div>
+
+<h3 id="help-urgent">Assume that every call for help is urgent</h3>
+
+<p>In addition to help, you might want to expose other information, such as copyright info, credits, terms of service, and privacy policy.</p>
+
+<p>Let users access this information through the Help menu item, but optimize the flow for people with urgent questions about how to do something or why something is happening in your app. The smaller subset of users who are looking for legal fine print or the names of the people who created the app won't be as burdened by taking a few extra steps.</p>
+
+<p>The same is true for any communication options you might want to provide, such as contacting customer support or submitting feedback. Offer these options in a way that doesn't add an extra step before users see help. When you put the help content forward, you increase the likelihood that users will find the answers on their own, which in turn reduces your support costs.</p>
+
+<p>When someone chooses "Help":</p>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-4">
+    <img src="{@docRoot}design/media/help_dont.png">
+  </div>
+  <div class="layout-content-col span-4">
+    <img src="{@docRoot}design/media/help_better.png">
+  </div>
+  <div class="layout-content-col span-5">
+    <img src="{@docRoot}design/media/help_evenbetter.png">
+  </div>  
+</div>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-4">
+    <h4 class="do-dont-label bad">Don't</h4>
+    <p>Present a dialog asking them to choose between help and other options.</p>
+  </div>
+  <div class="layout-content-col span-4">
+    <h4 class="do-dont-label good">Better</h4>
+    <p>Immediately launch a web browser with help content. Place other options in a footer.</p>
+  </div>
+  <div class="layout-content-col span-5">
+    <h4 class="do-dont-label good">Even Better</h4>
+    <p>Build a help screen in your app and offer other options in the action bar. For example, you could let users contact you with questions or feedback through an action button. The action overflow is the ideal place for non-help information that users rarely need.</p>
+    <p>This requires more development work than launching a web browser, but it's a nicer experience for users because they don't leave your app to get the help they need and doesn't require a network connection.</p>
+  </div>
+</div>
+
+<h2>Principles for Writing On-Screen Help Content</h2>
+
+<h4>Help is part of the UI</h4>
+<p>On-screen help is an extension of your app's UI, not a description of it. All words on the screen from the core app to the help should follow our <a href="{@docRoot}design/style/writing.html">Writing Style</a> principles so that the end-to-end experience feels seamless and cohesive.</p>
+
+<h4>Make every pixel count</h4>
+<p>It's not necessary to document every single detail about your app, especially things that are extremely apparent just by looking at the UI, or behaviors that are standard for the platform. Surface just the key additional information that the on-screen text doesn't have room to describe, in a way that makes it easy to map to the screen.</p>
+
+<h4>Pictures are faster than words</h4>
+<p>In describing key UI elements and providing step-by-step instructions, consider combining text with icons, partial screenshots with callouts, and other imagery. You'll need fewer words to explain things, and users will absorb the information more quickly.</p>
+
+<h4>Help me scan, not read</h4>
+<p>People don't read help from start to finish. They scan around, looking for a piece of information containing the answer they need. Make it less burdensome with friendly formatting and layout choices like bold headings, bulleted and numbered lists, tables, and white space between paragraphs. And if you have a large amount of content, divide it into multiple screens to cut down on scrolling.</p>
+
+<h4>Take me straight to the answer</h4>
+<p>What's better than a screen that's easy to scan? A screen that requires no scanning at all because the answer's right there. Consider having each screen in your app navigate to help that's relevant just to that screen. We call this <em>contextual help</em>, and it's the holy grail of user assistance. If you take this approach, be sure to also provide a way to get to the rest of the help content.</p>
\ No newline at end of file
diff --git a/docs/html/design/patterns/index.jd b/docs/html/design/patterns/index.jd
index 6f88e6d..4416de1 100644
--- a/docs/html/design/patterns/index.jd
+++ b/docs/html/design/patterns/index.jd
@@ -20,10 +20,10 @@
   <div id="text-overlay">
     Design apps that behave in a consistent, predictable fashion.
     <br><br>
-    <a href="{@docRoot}design/patterns/new-4-0.html" class="landing-page-link">New in Android 4.0</a>
+    <a href="{@docRoot}design/patterns/new.html" class="landing-page-link">New in Android</a>
   </div>
 
-  <a href="{@docRoot}design/patterns/new-4-0.html">
+  <a href="{@docRoot}design/patterns/new.html">
     <img src="{@docRoot}design/media/patterns_landing.png">
   </a>
 </div>
diff --git a/docs/html/design/patterns/multi-pane-layouts.jd b/docs/html/design/patterns/multi-pane-layouts.jd
index 0e63e32..ad888e9 100644
--- a/docs/html/design/patterns/multi-pane-layouts.jd
+++ b/docs/html/design/patterns/multi-pane-layouts.jd
@@ -26,8 +26,8 @@
 relationship between the panels.</p>
 <h2 id="orientation">Compound Views and Orientation Changes</h2>
 
-<p>Screens should have the same functionality regardless of orientation. If you use a compound view in
-one orientation, don't split it up when the user rotates the screen. There are several techniques
+<p>Screens should strive to have the same functionality regardless of orientation. If you use a compound view in
+one orientation, try not to split it up when the user rotates the screen. There are several techniques
 you can use to adjust the layout after orientation change while keeping functional parity intact.</p>
 
 <div class="layout-content-row">
@@ -67,9 +67,7 @@
   <div class="layout-content-col span-5">
 
 <h4>Expand/collapse</h4>
-<p>When the device rotates, collapse the left pane view to only show the most important information.
-Provide an <em>expand</em> control that allows the user to bring the left pane content back to its original
-width and vice versa.</p>
+<p>When the device rotates, collapse the left pane view to only show the most important information.</p>
 
   </div>
 </div>
@@ -83,9 +81,7 @@
   <div class="layout-content-col span-5">
 
 <h4>Show/hide</h4>
-<p>After rotating the device, show the right pane in fullscreen view. Use the Up icon in the action bar
-to show the left panel and allow navigation to a different email. Hide the left panel by touching
-the content in the detail panel.</p>
+<p>If your screen cannot accommodate the compound view on rotation show the right pane in full screen view on rotation to portrait. Use the Up icon in action bar to show the parent screen.</p>
 
   </div>
 </div>
@@ -104,7 +100,7 @@
 <p>Look for opportunities to consolidate your views into multi-panel compound views.</p>
 </li>
 <li>
-<p>Make sure that your screens provide functional parity after the screen orientation
+<p>Make sure that your screens try to provide functional parity after the screen orientation
   changes.</p>
 </li>
 </ul>
diff --git a/docs/html/design/patterns/new-4-0.jd b/docs/html/design/patterns/new-4-0.jd
deleted file mode 100644
index 91ebba7..0000000
--- a/docs/html/design/patterns/new-4-0.jd
+++ /dev/null
@@ -1,71 +0,0 @@
-page.title=New in Android 4.0
-@jd:body
-
-<div class="layout-content-row">
-  <div class="layout-content-col span-7">
-
-<h4>Navigation bar</h4>
-<p>Android 4.0 removes the need for traditional hardware keys on phones by replacing them with a
-virtual navigation bar that houses the Back, Home and Recents buttons. Read the
-<a href="{@docRoot}design/patterns/compatibility.html">Compatibility</a> pattern to learn how the OS adapts to
-phones with hardware buttons and how pre-Android 3.0 apps that rely on menu keys are supported.</p>
-
-  </div>
-  <div class="layout-content-col span-6">
-
-    <img src="{@docRoot}design/media/whats_new_nav_bar.png">
-
-  </div>
-</div>
-
-<div class="vspace size-2">&nbsp;</div>
-
-<div class="layout-content-row">
-  <div class="layout-content-col span-7">
-
-<h4>Action bar</h4>
-<p>The action bar is the most important structural element of an Android app. It provides consistent
-navigation across the platform and allows your app to surface actions.</p>
-
-  </div>
-  <div class="layout-content-col span-6">
-
-    <img src="{@docRoot}design/media/whats_new_action_bar.png">
-
-  </div>
-</div>
-
-<div class="vspace size-2">&nbsp;</div>
-
-<div class="layout-content-row">
-  <div class="layout-content-col span-7">
-
-<h4>Multi-pane layouts</h4>
-<p>Creating apps that scale well across different form factors and screen sizes is important in the
-Android world. Multi-pane layouts allow you to combine different activities that show separately on
-smaller devices into richer compound views for tablets.</p>
-
-  </div>
-  <div class="layout-content-col span-6">
-
-    <img src="{@docRoot}design/media/whats_new_multipanel.png">
-
-  </div>
-</div>
-
-<div class="vspace size-2">&nbsp;</div>
-
-<div class="layout-content-row">
-  <div class="layout-content-col span-7">
-
-<h4>Selection</h4>
-<p>The long press gesture which was traditionally used to show contextual actions for objects is now
-used for data selection. When selecting data, contextual action bars allow you to surface actions.</p>
-
-  </div>
-  <div class="layout-content-col span-6">
-
-    <img src="{@docRoot}design/media/whats_new_multiselect.png">
-
-  </div>
-</div>
diff --git a/docs/html/design/patterns/new.jd b/docs/html/design/patterns/new.jd
new file mode 100644
index 0000000..1fc4987
--- /dev/null
+++ b/docs/html/design/patterns/new.jd
@@ -0,0 +1,114 @@
+page.title=New in Android
+@jd:body
+
+<h2>Jelly Bean - Android 4.1</h2>
+
+<h4>Notifications</h4>
+<div class="layout-content-row">
+  <div class="layout-content-col span-7">
+    <p>Notifications have received some notable enhancements in Android 4.1:</p>
+    <ul>
+      <li>Users can act on notifications immediately from the drawer</li>
+      <li>Notifications are more flexible in size and layout</li>
+      <li>A priority flag helps sort notifications by importance</li>
+      <li>Notifications can be collapsed and expanded</li>
+    </ul>
+
+    <p>The base notification layout has not changed, so app notifications designed for versions earlier than Jelly Bean still look and work the same. Check the updated <a href="{@docRoot}design/patterns/notifications.html">Notifications</a> page for more details.</p>
+  </div>
+  <div class="layout-content-col span-6">
+    <img src="{@docRoot}design/media/new_notifications.png">
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<h4>Resizable Application Widgets</h4>
+<div class="layout-content-row">
+  <div class="layout-content-col span-7">
+    <p>Widgets are an essential aspect of home screen customization, allowing "at-a-glance" views of an app's most important data and functionality right from the user's home screen. Android 4.1 introduces improved App Widgets that can <strong>automatically resize and load different content</strong> based upon a number of factors including:</p>
+    <ul>
+      <li>Where the user drops them on the home screen</li>
+      <li>The size to which the user expands them</li>
+      <li>The amount of room available on the home screen</li>
+    </ul>
+
+    <p>You can supply separate landscape and portrait layouts for your widgets, which the system inflates as appropriate when the screen orientation changes. The Application Widgets has useful details about widget types, limitations, and design considerations.</p>
+  </div>
+  <div class="layout-content-col span-6">
+    <img src="{@docRoot}design/media/new_widgets.png">
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<h4>Accessibility</h4>
+<div class="layout-content-row">
+  <div class="layout-content-col span-11">
+    <p>One of Android's missions is to organize the world's information and make it universally accessible and useful. Our mission applies to all users-including people with disabilities such as visual impairment, color deficiency, hearing loss, and limited dexterity.</p>
+    <p>The new <a href="{@docRoot}design/patterns/accessibility.html">Accessibility</a> page provides details on how to design your app to be as accessible as possible by:</p>
+    <ul>
+      <li>Making navigation intuitive</li>
+      <li>Using recommended touch target sizes</li>
+      <li>Labeling visual UI elements meaningfully</li>
+      <li>Providing alternatives to affordances that time out</li>
+      <li>Using standard framework controls or enable TalkBack for custom controls</li>
+      <li>Trying it out yourself</li>
+    </ul>
+
+    <p>You can supply separate landscape and portrait layouts for your widgets, which the system inflates as appropriate when the screen orientation changes. The [Application Widgets] (should be link) has useful details about widget types, limitations, and design considerations.</p>
+  </div>
+  <div class="layout-content-col span-2">
+    <img src="{@docRoot}design/media/new_accessibility.png">
+  </div>
+</div>
+
+<h2>Ice Cream Sandwich - Android 4.0</h2>
+
+<h4>Navigation bar</h4>
+<div class="layout-content-row">
+  <div class="layout-content-col span-7">
+    <p>Android 4.0 removes the need for traditional hardware keys on phones by replacing them with a
+    virtual navigation bar that houses the Back, Home and Recents buttons. Read the <a href="{@docRoot}design/patterns/compatibility.html">Compatibility</a> pattern to learn how the OS adapts to phones with hardware buttons and how pre-Android 3.0 apps that rely on menu keys are supported.</p>
+  </div>
+  <div class="layout-content-col span-6">
+    <img src="{@docRoot}design/media/whats_new_nav_bar.png">
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<h4>Action bar</h4>
+<div class="layout-content-row">
+  <div class="layout-content-col span-7">
+    <p>The action bar is the most important structural element of an Android app. It provides consistent navigation across the platform and allows your app to surface actions.</p>
+  </div>
+  <div class="layout-content-col span-6">
+    <img src="{@docRoot}design/media/whats_new_action_bar.png">
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<h4>Multi-pane layouts</h4>
+<div class="layout-content-row">
+  <div class="layout-content-col span-7">
+    <p>Creating apps that scale well across different form factors and screen sizes is important in the Android world. Multi-pane layouts allow you to combine different activities that show separately on smaller devices into richer compound views for tablets.</p>
+  </div>
+  <div class="layout-content-col span-6">
+    <img src="{@docRoot}design/media/whats_new_multipanel.png">
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<h4>Selection</h4>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-7">
+    <p>The long press gesture which was traditionally used to show contextual actions for objects is now used for data selection. When selecting data, contextual action bars allow you to surface actions.</p>
+  </div>
+  <div class="layout-content-col span-6">
+    <img src="{@docRoot}design/media/whats_new_multiselect.png">
+  </div>
+</div>
diff --git a/docs/html/design/patterns/notifications.jd b/docs/html/design/patterns/notifications.jd
index ad88a01..75bfff2 100644
--- a/docs/html/design/patterns/notifications.jd
+++ b/docs/html/design/patterns/notifications.jd
@@ -1,20 +1,160 @@
 page.title=Notifications
 @jd:body
 
-<p>The notification system allows your app to keep the user informed about important events, such as
-new messages in a chat app or a calendar event.</p>
-<p>To create an app that feels streamlined, pleasant, and respectful, it is important to design your
-notifications carefully. Notifications embody your app's voice, and contribute to your app's
-personality. Unwanted or unimportant notifications can annoy the user, so use them judiciously.</p>
+<p>The notification system allows your app to keep the user informed about events, such as new chat messages or a calendar event. Think of notifications as a news channel that alerts the user to important events as they happen or a log that chronicles events while the user is not paying attention.</p>
+
+<h4>New in Jelly Bean</h4>
+<p>In Jelly Bean, notifications received their most important structural and functional update since the beginning of Android.</p>
+<ul>
+  <li>Notifications can include actions that enable the user to immediately act on a notification from the notification drawer.</li>
+  <li>Notifications are now more flexible in size and layout. They can be expanded to show additional information details.</li>
+  <li>A priority flag was introduced that helps to sort notifications by importance rather than time only.</li>
+</ul>
+
+<h2>Anatomy of a notification</h2>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+    <h4>Base Layout</h4>
+    <p>At a minimum, all notifications consist of a base layout, including:</p>
+    <ul>
+      <li>the sending application's notification icon or the sender's photo</li>
+      <li>a notification title and message</li>
+      <li>a timestamp</li>
+      <li>a secondary icon to identify the sending application when the senders image is shown for the main icon</li>
+    </ul>
+    <p>The information arrangement of the base layout has not changed in Jelly Bean, so app notifications designed for versions earlier than Jelly Bean still look and work the same.</p>
+  </div>
+  <div class="layout-content-col span-6">
+    <img src="{@docRoot}design/media/notifications_pattern_anatomy.png">
+    <div class="figure-caption">
+      Base layout of a notification
+    </div>
+  </div>
+</div>
+
+<h4>Expanded layouts</h4>
+<p>With Jelly Bean you have the option to provide more event detail. You can use this to show the first few lines of a message or show a larger image preview. This provides the user with additional context, and - in some cases - may allow the user to read a message in its entirety. The user can pinch-zoom or two-finger glide in order to toggle between base and expanded layouts. For single event notifications, Android provides two expanded layout templates (text and image) for you to re-use in your application.</p>
+
+<img src="{@docRoot}design/media/notifications_pattern_expandable.png">
+
+<h4>Actions</h4>
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+    <p>Starting with Jelly Bean, Android supports optional actions that are displayed at the bottom of the notification. With actions, users can handle the most common tasks for a particular notification from within the notification shade without having to open the originating application. This speeds up interaction and, in conjunction with "swipe-to-dismiss", helps users to streamline their notification triaging experience.</p>
+    <p>Be judicious with how many actions you include with a notification. The more actions you include, the more cognitive complexity you create. Limit yourself to the fewest number of actions possible by only including the most imminently important and meaningful ones.</p>
+    <p>Good candidates for actions on notifications are actions that are:</p>
+    <ul>
+      <li>essential, frequent and typical for the content type you're displaying</li>
+      <li>time-critical</li>
+      <li>not overlapping with neighboring actions</li>
+    </ul>
+    <p>Avoid actions that are:</p>
+    <ul>
+      <li>ambiguous</li>
+      <li>duplicative of the default action of the notification (such as "Read" or "Open")</li>
+    </ul>
+  </div>
+  <div class="layout-content-col span-7">
+    <img src="{@docRoot}design/media/notifications_pattern_two_actions.png">
+    <div class="figure-caption">
+      Calendar reminder notification with two actions
+    </div>
+  </div>
+</div>
+
+<p>You can specify a maximum of three actions, each consisting of an action icon and an action name. Adding actions to a simple base layout will make the notification expandable, even if the notification doesn't have an expanded layout. Since actions are only shown for expanded notifications and are otherwise hidden, you must make sure that any action a user can invoke from a notification is available from within the associated application as well.</p>
+
+<h2>Design guidelines</h2>
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+    <img src="{@docRoot}design/media/notifications_pattern_personal.png">
+  </div>
+  <div class="layout-content-col span-7">
+    <h4>Make it personal</h4>
+    <p>For notifications of items sent by another user (such as a message or status update), include that person's image.</p>
+    <p>Remember to include the app icon as a secondary icon in the notification, so that the user can still identify which app posted it.</p>
+  </div>
+</div>
+
+<h4>Navigate to the right place</h4>
+<p>When the user touches the body of a notification (outside of the action buttons), open your app to the place where the user can consume and act upon the data referenced in the notification. In most cases this will be the detail view of a
+single data item such as a message, but it might also be a summary view if the notification is stacked (see <em>Stacked notifications</em> below) and references multiple items. If in any of those cases the user is taken to a hierarchy level below your app's top-level, insert navigation into your app's back stack to allow them to navigate to your app's top level using the system back key. For more
+information, see the chapter on <em>System-to-app navigation</em> in the <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> design pattern.</p>
+
+<h4>Correctly set and manage notification priority</h4>
+<p>Starting with Jelly Bean, Android now supports a priority flag for notifications. It allows you to influence where your notification will appear in comparison to other notifications and help to make sure that users always see their most important notifications first. You can choose from the following priority levels when posting a notification:</p>
+
+<table>
+  <tr>
+    <th><strong>Priority</strong></th>
+    <th><strong>Use</strong></th>
+  </tr>
+  <tr>
+    <td>MAX</td>
+    <td>Use for critical and urgent notifications that alert the user to a condition that is time-critical or needs to be resolved before they can continue with a particular task.</td>
+  </tr>
+  <tr>
+    <td>HIGH</td>
+    <td>Use high priority notifications primarily for important communication, such as message or chat events with content that is particularly interesting for the user.</td>
+  </tr>
+  <tr>
+    <td>DEFAULT</td>
+    <td>The default priority. Keep all notifications that don't fall into any of the other categories at this priority level.</td>
+  </tr>
+  <tr>
+    <td>LOW</td>
+    <td>Use for notifications that you still want the user to be informed about, but that rate low in urgency.</td>
+  </tr>
+  <tr>
+    <td>MIN</td>
+    <td>Contextual/background information (e.g. weather information, contextual location information). Minimum     priority notifications will not show in the status bar. The user will only discover them when they expand the notification tray.</td>
+  </tr>
+</table>
+<img src="{@docRoot}design/media/notifications_pattern_priority.png">
+
+<h4>Stack your notifications</h4>
+<p>If your app creates a notification while another of the same type is still pending, avoid creating
+an altogether new notification object. Instead, stack the notification.</p>
+<p>A stacked notification builds a summary description and allows the user to understand how many
+notifications of a particular kind are pending.</p>
+<p><strong>Don't</strong>:</p>
+
+<img src="{@docRoot}design/media/notifications_pattern_additional_fail.png">
+
+<p><strong>Do</strong>:</p>
+
+<img src="{@docRoot}design/media/notifications_pattern_additional_win.png">
+
+<p>You can provide more detail about the individual notifications that make up a stack by using the expanded digest layout. This allows users to gain a better sense of which notifications are pending and if they are interesting enough to be read in detail within the associated app.</p>
+
+<img src="{@docRoot}design/media/notifications_expand_contract_msg.png">
+
+<h4>Make notifications optional</h4>
+<p>Users should always be in control of notifications. Allow the user to disable your apps notifications or change their alert properties, such as alert sound and whether to use vibration, by adding a notification settings item to your application settings.</p>
+<h4>Use distinct icons</h4>
+<p>By glancing at the notification area, the user should be able to discern what kinds of notifications are currently pending.</p>
+
+<div class="do-dont-label good"><strong>Do</strong></div>
+<p style="margin-top:0;">Look at the notification icons the Android apps already provide and create notification icons for your app that are sufficiently distinct in appearance.</p>
+<div class="do-dont-label good"><strong>Do</strong></div>
+<p style="margin-top:0;">Use the proper <a href="{@docRoot}design/style/iconography.html#notification">notification icon style</a> for small icons, and the Holo Dark <a href="{@docRoot}design/style/iconography.html#action-bar">action bar icon style</a> for your action icons.</p>
+<div class="do-dont-label good"><strong>Do</strong></div>
+<p style="margin-top:0;">Keep your icons visually simple and avoid excessive detail that is hard to discern.</p>
+<div class="do-dont-label bad"><strong>Don't</strong></div>
+<p style="margin-top:0;">Use color to distinguish your app from others.</p>
+
+<h4>Pulse the notification LED appropriately</h4>
+<p>Many Android devices contain a tiny lamp, called the notification <acronym title="Light-Emitting Diode">LED</acronym>, which is used to keep the user informed about events while the screen is off. Notifications with a priority level of MAX, HIGH, or DEFAULT should cause the LED to glow, while those with lower priority (LOW and MIN) should not.</p>
+
+<p>The user's control over notifications should extend to the LED. By default, the LED will glow with a white color. Your notifications shouldn't use a different color unless the user has explicitly customized it.</p>
+
+<h2>Building notifications that users care about</h2>
+<p>To create an app that feels streamlined, pleasant, and respectful, it is important to design your notifications carefully. Notifications embody your app's voice, and contribute to your app's personality. Unwanted or unimportant notifications can annoy the user, so use them judiciously.</p>
+
 <h4>When to display a notification</h4>
-<p>To create an application that people love, it's important to recognize that the user's attention and
-focus is a resource that must be protected. To use an analogy that might resonate with software
-developers, the user is not a method that can be invoked to return a value.  The user's focus is a
-resource more akin to a thread, and creating a notification momentarily blocks the user thread as
-they process and then dismiss the interruptive notification.</p>
-<p>Android's notification system has been designed to quickly inform users of events while they focus
-on a task, but it is nonetheless still important to be conscientious when deciding to create a
-notification.</p>
+<p>To create an application that people love, it's important to recognize that the user's attention and focus is a resource that must be protected. While Android's notification system has been designed to minimize the impact of notifications on the users attention, it is nonetheless still important to be aware of the fact that notifications are potentially interrupting the users task flow. As you plan your notifications, ask yourself if they are important enough to warrant an interruption. If you are unsure, allow the user to opt into a notification using your apps notification settings or adjust the notifications priority flag.</p>
+<p>Time sensitive events are great opportunities for valuable notifications with high priority, especially if these synchronous events involve other people. For instance, an incoming chat is a real time and synchronous form of communication: there is another user actively waiting on you to respond. Calendar events are another good example of when to use a notification and grab the user's attention, because the event is imminent, and calendar events often involve other people.</p>
 <p>While well behaved apps generally only speak when spoken to, there are some limited cases where an
 app actually should interrupt the user with an unprompted notification.</p>
 <p>Notifications should be used primarily for <strong>time sensitive events</strong>, and especially if these
@@ -34,27 +174,19 @@
 <p>There are however many other cases where notifications should not be used:</p>
 <ul>
 <li>
-<p>Don't notify the user of information that is not directed specifically at them, or information
-that is not truly time sensitive.  For instance the asynchronous and undirected updates flowing
-through a social network do not warrant a real time interruption.</p>
+<p>Avoid notifying the user of information that is not directed specifically at them, or information that is not truly time sensitive. For instance the asynchronous and undirected updates flowing through a social network generally do not warrant a real time interruption. For the users that do care about them, allow them to opt-in.</p>
 </li>
 <li>
-<p>Don't create a notification if the relevant new information is currently on screen. Instead, use
-the UI of the application itself to notify the user of new information directly in context. For
-instance, a chat application should not create system notifications while the user is actively
-chatting with another user.</p>
+<p>Don't create a notification if the relevant new information is currently on screen. Instead, use the UI of the application itself to notify the user of new information directly in context. For instance, a chat application should not create system notifications while the user is actively chatting with another user.</p>
 </li>
 <li>
-<p>Don't interrupt the user for low level technical operations, like saving or syncing information,
-or updating an application, if it is possible for the system to simply take care of itself without
-involving the user.</p>
+<p>Don't interrupt the user for low level technical operations, like saving or syncing information, or updating an application, if it is possible for the system to simply take care of itself without involving the user.</p>
 </li>
 <li>
-<p>Don't interrupt the user to inform them of an error if it is possible for the application to
-quickly recover from the error on its own without the user taking any action.</p>
+<p>Don't interrupt the user to inform them of an error if it is possible for the application to quickly recover from the error on its own without the user taking any action.</p>
 </li>
 <li>
-<p>Don't use notifications for services that the user cannot manually start or stop.</p>
+<p>Don't create notifications that have no true notification content and merely advertise your app. A notification should inform the user about a state and should not be used to merely launch an app.</p>
 </li>
 <li>
 <p>Don't create superfluous notifications just to get your brand in front of users. Such
@@ -66,108 +198,10 @@
 
   </div>
   <div class="layout-content-col span-6">
-
     <img src="{@docRoot}design/media/notifications_pattern_social_fail.png">
-
   </div>
 </div>
 
-<h2 id="design-guidelines">Design Guidelines</h2>
-
-<div class="layout-content-row">
-  <div class="layout-content-col span-6">
-
-    <img src="{@docRoot}design/media/notifications_pattern_anatomy.png">
-
-  </div>
-  <div class="layout-content-col span-6">
-
-<h4>Make it personal</h4>
-<p>For notifications of items sent by another user (such as a message or status update), include that
-person's image.</p>
-<p>Remember to include the app icon as a secondary icon in the notification, so that the user can
-still identify which app posted it.</p>    
-
-  </div>
-</div>
-
-<h4>Navigate to the right place</h4>
-<p>When the user touches a notification, be open your app to the place where the user can consume and
-act upon the data referenced in the notification. In most cases this will be the detail view of a
-single data item (e.g. a message), but it might also be a summary view if the notification is
-stacked (see <em>Stacked notifications</em> below) and references multiple items. If in any of those cases
-the user is taken to a hierarchy level below your app's top-level, insert navigation into your app's
-back stack to allow them to navigate to your app's top level using the system back key. For more
-information, see the chapter on <em>System-to-app navigation</em> in the
-<a href="{@docRoot}design/patterns/navigation.html">Navigation</a> design pattern.</p>
-<h4>Timestamps for time sensitive events</h4>
-<p>By default, standard Android notifications include a timestamp in the upper right corner. Consider
-whether the timestamp is valuable in the context of your notification. If the timestamp is not
-valuable, consider if the event is important enough to warrant grabbing the user's attention with a
-notification. If the notification is important enough, decide if you would like to opt out of
-displaying the timestamp.</p>
-<p>Include a timestamp if the user likely needs to know how long ago the notification occurred. Good
-candidates for timestamps include communication notifications (email, messaging, chat, voicemail)
-where the user may need the timestamp information to understand the context of a message or to
-tailor a response.</p>
-<h4>Stack your notifications</h4>
-<p>If your app creates a notification while another of the same type is still pending, avoid creating
-an altogether new notification object. Instead, stack the notification.</p>
-<p>A stacked notification builds a summary description and allows the user to understand how many
-notifications of a particular kind are pending.</p>
-<p><strong>Don't</strong>:</p>
-
-<img src="{@docRoot}design/media/notifications_pattern_additional_fail.png">
-
-<p><strong>Do</strong>:</p>
-
-<img src="{@docRoot}design/media/notifications_pattern_additional_win.png">
-
-<p>If you keep the summary and detail information on different screens, a stacked notification may need
-to open to a different place in the app than a single notification.</p>
-<p>For example, a single email notification should always open to the content of the email, whereas a
-stacked email notification opens to the Inbox view.</p>
-<h4>Clean up after yourself</h4>
-<p>Just like calendar events, some notifications alert the user to an event that happens at a
-particular point in time. After that moment has passed, the notification is likely not important to
-the user anymore, and you should consider removing it automatically.  The same is true for active
-chat conversations or voicemail messages the user has listened to, users should not have to manually
-dismiss notifications independently from taking action on them.</p>
-
-<div class="vspace size-1">&nbsp;</div>
-
-<div class="layout-content-row">
-  <div class="layout-content-col span-7">
-
-<h4>Provide a peek into your notification</h4>
-<p>You can provide a short preview of your notification's content by providing optional ticker text.
-The ticker text is shown for a short amount of time when the notification enters the system and then
-hides automatically.</p>
-
-  </div>
-  <div class="layout-content-col span-6">
-
-    <img src="{@docRoot}design/media/notifications_pattern_phone_ticker.png">
-
-  </div>
-</div>
-
-<h4>Make notifications optional</h4>
-<p>Users should always be in control of notifications. Allow the user to silence the notifications from
-your app by adding a notification settings item to your application settings.</p>
-<h4>Use distinct icons</h4>
-<p>By glancing at the notification area, the user should be able to discern what notification types are
-currently pending.</p>
-<p><strong>Do</strong>:</p>
-<ul>
-<li>Look at the notification icons the Android apps already provide and create notification icons for
-  your app that are sufficiently distinct in appearance.</li>
-</ul>
-<p><strong>Don't</strong>:</p>
-<ul>
-<li>Use color to distinguish your app from others. Notification icons should generally be monochrome.</li>
-</ul>
-
 <h2 id="interacting-with-notifications">Interacting With Notifications</h2>
 
 <div class="layout-content-row">
@@ -178,11 +212,8 @@
   </div>
   <div class="layout-content-col span-6">
 
-<p>Notifications are indicated by icons in the notification area and can be accessed by opening the
-notification drawer.</p>
-<p>Inside the drawer, notifications are chronologically sorted with the latest one on top. Touching a
-notification opens the associated app to detailed content matching the notification. Swiping left or
-right on a notification removes it from the drawer.</p>
+  <p>Notifications are indicated by icons in the notification area and can be accessed by opening the notification drawer.</p>
+  <p>Inside the drawer, notifications are chronologically sorted with the latest one on top. Touching a notification opens the associated app to detailed content matching the notification. Swiping left or right on a notification removes it from the drawer.</p>
 
   </div>
 </div>
@@ -190,8 +221,7 @@
 <div class="layout-content-row">
   <div class="layout-content-col span-6">
 
-<p>On tablets, the notification area is integrated with the system bar at the bottom of the screen. The
-notification drawer is opened by touching anywhere inside the notification area.</p>
+<p>On tablets, the notification area is integrated with the system bar at the bottom of the screen. The notification drawer is opened by touching anywhere inside the notification area.</p>
 
   </div>
   <div class="layout-content-col span-6">
@@ -210,27 +240,14 @@
   <div class="layout-content-col span-6">
 
 <h4>Ongoing notifications</h4>
-<p>Ongoing notifications keep users informed about an ongoing process in the background. For example,
-music players announce the currently playing track in the notification system and continue to do so
-until the user stops the playback. They can also be used to show the user feedback for longer tasks
-like downloading a file, or encoding a video. Ongoing notifications cannot be manually removed from
-the notification drawer.</p>
+<p>Ongoing notifications keep users informed about an ongoing process in the background. For example, music players announce the currently playing track in the notification system and continue to do so until the user stops the playback. They can also be used to show the user feedback for longer tasks like downloading a file, or encoding a video. Ongoing notifications cannot be manually removed from the notification drawer.</p>
 
   </div>
 </div>
 
 <div class="layout-content-row">
   <div class="layout-content-col span-12">
-
-<h4>Dialogs and toasts are for feedback not notification</h4>
-<p>Your app should not create a dialog or toast if it is not currently on screen. Dialogs and Toasts
-should only be displayed as the immediate response to the user taking an action inside of your app.
-For instance, dialogs can be used to confirm that the user understands the severity of an action,
-and toasts can echo back that an action has been successfully taken.</p>
-
+    <h4>Dialogs and toasts are for feedback not notification</h4>
+    <p>Your app should not create a dialog or toast if it is not currently on screen. Dialogs and Toasts should only be displayed as the immediate response to the user taking an action inside of your app. For further guidance on the use of dialogs and toasts, refer to <a href="{@docRoot}design/patterns/confirming-acknowledging.html">Confirming &amp; Acknowledging</a>.</p>
   </div>
-</div>
-
-<div class="vspace size-1">&nbsp;</div>
-
-<img src="{@docRoot}design/media/notifications_pattern_dialog_toast.png">
+</div>
\ No newline at end of file
diff --git a/docs/html/design/patterns/selection.jd b/docs/html/design/patterns/selection.jd
index e3ee90e..612c370 100644
--- a/docs/html/design/patterns/selection.jd
+++ b/docs/html/design/patterns/selection.jd
@@ -1,8 +1,7 @@
 page.title=Selection
 @jd:body
 
-<p>Android 3.0 introduced the <em>long press</em> gesture&mdash;that is, a touch that's held in the same
-position for a moment&mdash;as the global gesture to select data. This affects the way you should
+<p>Android 3.0 changed the <em>long press</em> gesture&mdash;that is, a touch that's held in the same position for a moment&mdash;to be the global gesture to select data.. This affects the way you should
 handle multi-select and contextual actions in your apps.</p>
 
 <div class="vspace size-1">&nbsp;</div>
diff --git a/docs/html/design/patterns/settings.jd b/docs/html/design/patterns/settings.jd
index 3b28b84..d10f0d3 100644
--- a/docs/html/design/patterns/settings.jd
+++ b/docs/html/design/patterns/settings.jd
@@ -429,7 +429,7 @@
     <tbody>
       <tr>
         <td class="secondary-text">
-        After 10 minutes of activity
+        After 10 minutes of inactivity
         </td>
       </tr>
     </tbody>
@@ -551,7 +551,7 @@
     <tbody>
       <tr>
         <td class="secondary-text">
-        After 10 minutes of activity
+        After 10 minutes of inactivity
         </td>
       </tr>
     </tbody>
diff --git a/docs/html/design/patterns/swipe-views.jd b/docs/html/design/patterns/swipe-views.jd
index 95d65dd..252343d 100644
--- a/docs/html/design/patterns/swipe-views.jd
+++ b/docs/html/design/patterns/swipe-views.jd
@@ -24,7 +24,12 @@
 
 <img src="{@docRoot}design/media/swipe_views2.png">
 <div class="figure-caption">
-  Navigating between consecutive Email messages using the swipe gesture.
+  Navigating between consecutive Email messages using the swipe gesture. If a view contains content that exceeds the width of the screen such as a wide Email message, make sure the user's initial swipes will scroll horizontally within the view. Once the end of the content is reached, an additional swipe should navigate to the next view. In addition, support the use of edge swipes to immediately navigate between views when content scrolls horizontally.
+</div>
+
+<img src="{@docRoot}design/media/swipe_views3.png">
+<div class="figure-caption">
+  Scrolling within a wide Email message using the swipe gesture before navigating to the next message.
 </div>
 
 <h2 id="between-tabs">Swiping Between Tabs</h2>
@@ -46,29 +51,29 @@
 
   </div>
   <div class="layout-content-col span-8">
+    <p>If your app uses action bar tabs, use swipe to navigate between the different views.</p>
+    <div class="vspace size-1">&nbsp;</div>
 
-<p>If your app uses action bar tabs, use swipe to navigate between the different views.</p>
-<div class="vspace size-2">&nbsp;</div>
-
-<h2 id="checklist">Checklist</h2>
-
-<ul>
-<li>
-<p>Use swipe to quickly navigate between detail views or tabs.</p>
-</li>
-<li>
-<p>Transition between the views as the user performs the swipe gesture. Do not wait for the
-  gesture to complete and then transition between views.</p>
-</li>
-<li>
-<p>If you used buttons in the past for previous/next navigation, replace them with
-  the swipe gesture.</p>
-</li>
-<li>
-<p>Consider adding contextual information in your detail view that informs the user about the
-  relative list position of the currently visible item.</p>
-</li>
-</ul>
-
+    <h2 id="checklist">Checklist</h2>
+    <ul>
+      <li>
+      <p>Use swipe to quickly navigate between detail views or tabs.</p>
+      </li>
+      <li>
+      <p>Transition between the views as the user performs the swipe gesture. Do not wait for the
+        gesture to complete and then transition between views.</p>
+      </li>
+      <li>
+      <p>If you used buttons in the past for previous/next navigation, replace them with
+        the swipe gesture.</p>
+      </li>
+      <li>
+      <p>Consider adding contextual information in your detail view that informs the user about the
+        relative list position of the currently visible item.</p>
+      </li>
+      <li>
+      <p>For more details on how to build swipe views, read the developer documentation on <a href="{@docRoot}training/implementing-navigation/lateral.html#horizontal-paging">Implementing Lateral Navigation</a>.</p>
+      </li>
+    </ul>
   </div>
 </div>
diff --git a/docs/html/design/patterns/widgets.jd b/docs/html/design/patterns/widgets.jd
new file mode 100644
index 0000000..cf4c74f
--- /dev/null
+++ b/docs/html/design/patterns/widgets.jd
@@ -0,0 +1,131 @@
+page.title=Widgets
+@jd:body
+
+<p>Widgets are an essential aspect of home screen customization. You can imagine them as "at-a-glance" views of an app's most important data and functionality that is accessible right from the user's home screen. Users can move widgets across their home screen panels, and, if supported, resize them to tailor the amount of information within a widget to their preference.</p>
+
+<h2>Widget types</h2>
+<p>As you begin planning your widget, think about what kind of widget you're trying to build. Widgets typically fall into one of the following categories:</p>
+
+<h3>Information widgets</h3>
+<img style="float:right;" src="{@docRoot}design/media/widgets_info.png">
+<p>Information widgets typically display a few crucial information elements that are important to a user and track how that information changes over time. Good examples for information widgets are weather widgets, clock widgets or sports score trackers. Touching information widgets typically launches the associated app and opens a detail view of the widget information.</p>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+    <h3>Collection widgets</h3>
+    <p>As the name implies, collection widgets specialize on displaying multitude elements of the same type, such as a collection of pictures from a gallery app, a collection of articles from a news app or a collection of emails/messages from a communication app. Collection widgets typically focus on two use cases: browsing the collection, and opening an element of the collection to its detail view for consumption. Collection widgets can scroll vertically.</p>
+  </div>
+  <div class="layout-content-col span-3">
+    <img src="{@docRoot}design/media/widgets_collection_gmail.png">
+    <div class="figure-caption">
+      ListView widget
+    </div>
+  </div>
+  <div class="layout-content-col span-4">
+    <img src="{@docRoot}design/media/widgets_collection_bookmarks.png">
+    <div class="figure-caption">
+      GridView widget
+    </div>
+  </div>
+</div>
+
+<h3>Control widgets</h3>
+<img style="float:right;" src="{@docRoot}design/media/widgets_control.png">
+<p>The main purpose of a control widget is to display often used functions that the user can trigger right from the home screen without having to open the app first. Think of them as remote controls for an app. A typical example of control widgets are music app widgets that allow the user to play, pause or skip music tracks from outside the actual music app.</p>
+<p>Interacting with control widgets may or may not progress to an associated detail view depending on if the control widget's function generated a data set, such as in the case of a search widget.</p>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<h3>Hybrid widgets</h3>
+<img style="float:right;" src="{@docRoot}design/media/widgets_hybrid.png">
+<p>While all widgets tend to gravitate towards one of the three types described above, many widgets in reality are hybrids that combine elements of different types.</p>
+<p>For the purpose of your widget planning, center your widget around one of the base types and add elements of other types if needed.</p>
+<div class="figure-caption">
+A music player widget is primarily a control widget, but also keeps the user informed about what track is currently playing. It essentially combines a control widget with elements of an information widget type.
+</div>
+
+<h2>Widget limitations</h2>
+<p>While widgets could be understood as "mini apps", there are certain limitations that are important to understand before you start to embark on designing your widget:</p>
+
+<h3>Gestures</h3>
+<p>Because widgets live on the home screen, they have to co-exist with the navigation that is established there. This limits the gesture support that is available in a widget compared to a full-screen app. While apps for example may support a view pager that allows the user to navigate between screens laterally, that gesture is already taken on the home screen for the purpose of navigating between home panels.</p>
+<p>The only gestures available for widgets are:</p>
+<ul>
+  <li>Touch</li>
+  <li>Vertical swipe</li>
+</ul>
+<img src="{@docRoot}design/media/widgets_gestures.png">
+
+<h3>Elements</h3>
+<p>Given the above interaction limitations, some of the UI building blocks that rely on restricted gestures are not available for widgets. For a complete list of supported building blocks and more information on layout restrictions, please refer to the "Creating App Widget Layouts" section in the <a href="{@docRoot}guide/topics/appwidgets/index.html">App Widgets</a> API Guide.</p>
+
+<h2>Design guidelines</h2>
+
+<h3>Widget content</h3>
+<p>Widgets are a great mechanism to attract a user to your app by "advertising" new and interesting content that is available for consumption in your app.</p>
+<p>Just like the teasers on the front page of a newspaper, widgets should consolidate and concentrate an app's information and then provide a connection to richer detail within the app; or in other words: the widget is the information "snack" while the app is the "meal." As a bottom line, always make sure that your app shows more detail about an information item than what the widget already displays.</p>
+
+<h3>Widget navigation</h3>
+<p>Besides the pure information content, you should also consider to round out your widget's offering by providing navigation links to frequently used areas of your app. This lets users complete tasks quicker and extends the functional reach of the app to the home screen.</p>
+<p>Good candidates for navigation links to surface on widgets are:</p>
+<ul>
+  <li>Generative functions: These are the functions that allow the user to create new content for an app, such as creating a new document or a new message.</li>
+  <li>Open application at top level: Tapping on an information element will usually navigate the user to a lower level detail screen. Providing access to the top level of your application provides more navigation flexibility and can replace a dedicated app shortcut that users would otherwise use to navigate to the app from the home screen. Using your application icon as an affordance can also provide your widget with a clear identity in case the data you're displaying is ambiguous.</li>
+</ul>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+    <h3>Widget resizing</h3>
+    <p>With version 3.1, Android introduced resizable widgets to the platform. Resizing allows users to adjust the height and/or the width of a widget within the constraints of the home panel placement grid. You can decide if your widget is freely resizable or if it is constrained to horizontal or vertical size changes. You do not have to support resizing if your particular widget is inherently fixed-size.</p>
+    <p>Allowing users to resize widgets has important benefits:</p>
+    <ul>
+      <li>They can fine-tune how much information they want to see on each widget.</li>
+      <li>They can better influence the layout of widgets and shortcuts on their home panels.</li>
+    </ul>
+  </div>
+
+  <div class="layout-content-col span-7">
+    <img src="{@docRoot}design/media/widgets_resizing01.png">
+    <div class="figure-caption">
+      A long press and subsequent release sets resizable widgets into resize mode. Users can use the drag handles or the widget corners to set the desired size.
+    </div>
+  </div>
+</div>
+
+<p>Planning a resize strategy for your widget depends on the type of widget you're creating. List or grid-based collection widgets are usually straightforward because resizing the widget will simply expand or contract the vertical scrolling area. Regardless of the of the widget's size, the user can still scroll all information elements into view. Information widgets on the other hand require a bit more hands-on planning, since they are not scrollable and all content has to fit within a given size. You will have to dynamically adjust your widget's content and layout to the size the user defined through the resize operation.</p>
+<img src="{@docRoot}design/media/widgets_resizing02.png">
+<p>In this simple example the user can horizontally resize a weather widget in 4 steps and expose richer information about the weather at the current location as the widget grows.</p>
+<p>For each widget size determine how much of your app's information should surface. For smaller sizes concentrate on the essential and then add more contextual information as the widget grows horizontally and vertically.</p>
+
+<h3>Layout considerations</h3>
+<p>It will be tempting to layout your widgets according to the dimensions of the placement grid of a particular device that you own and develop with. This can be a useful initial approximation as you layout your widget, but keep the following in mind:</p>
+<ul>
+  <li>The number, size and spacing of cells can vary widely from device to device, and hence it is very important that your widget is flexible and can accommodate more or less space than anticipated.</li>
+  <li>In fact, as the user resizes a widget, the system will respond with a dp size range in which your widget can redraw itself. Planning your widget resizing strategy across "size buckets" rather than variable grid dimensions will give you the most reliable results.</li>
+</ul>
+
+<h3>Widget configuration</h3>
+<div class="layout-content-row">
+  <div class="layout-content-col span-6">
+    <p>Sometimes widgets need to be setup before they can become useful. Think of an email widget for example, where you need to provide an account before the inbox can be displayed. Or a static photo widget where the user has to assign the picture that is to be displayed from the gallery.</p>
+    <p>Android widgets display their configuration choices right after the widget is dropped onto a home panel. Keep the widget configuration light and don't present more than 2-3 configuration elements. Use dialog-style instead of full-screen activities to present configuration choices and retain the user's context of place, even if doing so requires use of multiple dialogs.</p>
+<p>Once setup, there typically is not a lot of reason to revisit the setup. Therefore Android widgets do not show a "Setup" or "Configuration" button.</p>
+  </div>
+
+  <div class="layout-content-col span-6">
+    <img src="{@docRoot}design/media/widgets_config.png">
+    <div class="figure-caption">
+      After adding a Play widget to a home panel, the widget asks the user to specify the type of media the widget should display.
+    </div>
+  </div>
+</div>
+
+<h3>Checklist</h3>
+<ul>
+  <li>Focus on small portions of glanceable information on your widget. Expand on the information in your app.</li>
+  <li>Choose the right widget type for your purpose.</li>
+  <li>For resizable widgets, plan how the content for your widget should adapt to different sizes.</li>
+  <li>Make your widget orientation and device independent by ensuring that the layout is capable of stretching and contracting.</li>
+</ul>
\ No newline at end of file
diff --git a/docs/html/design/style/color.jd b/docs/html/design/style/color.jd
index 9c7b6b6..5be34ac 100644
--- a/docs/html/design/style/color.jd
+++ b/docs/html/design/style/color.jd
@@ -115,7 +115,7 @@
 
 <p>Blue is the standard accent color in Android's color palette. Each color has a corresponding darker
 shade that can be used as a complement when needed.</p>
-<p><a href="https://dl-ssl.google.com/android/design/Android_Design_Color_Swatches_20120229.zip">Download the swatches</a></p>
+<p><a href="{@docRoot}downloads/design/Android_Design_Color_Swatches_20120229.zip">Download the swatches</a></p>
 
 <img src="{@docRoot}design/media/color_spectrum.png">
 
diff --git a/docs/html/design/style/iconography.jd b/docs/html/design/style/iconography.jd
index 775e45d..31274c5 100644
--- a/docs/html/design/style/iconography.jd
+++ b/docs/html/design/style/iconography.jd
@@ -110,7 +110,7 @@
 </p>
 <p>
 
-<a href="https://dl-ssl.google.com/android/design/Android_Design_Icons_20120229.zip">Download the Action Bar Icon Pack</a>
+<a href="{@docRoot}downloads/design/Android_Design_Icons_20120229.zip">Download the Action Bar Icon Pack</a>
 
 </p>
 
diff --git a/docs/html/design/style/typography.jd b/docs/html/design/style/typography.jd
index db2fb5f..a699bed 100644
--- a/docs/html/design/style/typography.jd
+++ b/docs/html/design/style/typography.jd
@@ -18,8 +18,8 @@
 
     <img src="{@docRoot}design/media/typography_alphas.png">
 
-<p><a href="https://dl-ssl.google.com/android/design/Roboto_Hinted_20111129.zip">Download Roboto</a></p>
-<p><a href="https://dl-ssl.google.com/android/design/Roboto_Specimen_Book_20111129.pdf">Specimen Book</a></p>
+<p><a href="{@docRoot}downloads/design/Roboto_Hinted_20111129.zip">Download Roboto</a></p>
+<p><a href="{@docRoot}downloads/design/Roboto_Specimen_Book_20111129.pdf">Specimen Book</a></p>
 
   </div>
 </div>
diff --git a/docs/html/design/videos/index.jd b/docs/html/design/videos/index.jd
new file mode 100644
index 0000000..272183f
--- /dev/null
+++ b/docs/html/design/videos/index.jd
@@ -0,0 +1,67 @@
+page.title=Videos
+@jd:body
+
+<p>The Android Design Team was pleased to present five fantastic design-oriented sessions at Google I/O 2012. Visit these pages to view the videos and presentations from the conference.</p>
+<img src="{@docRoot}design/media/extras_googleio_12.png">
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-7">
+    <h3 id="design-for-success"><a href="https://developers.google.com/events/io/sessions/gooio2012/112/">Android Design for Success</a></h3>
+    <p>You have a great idea for an Android app. You want it to stand out among hundreds of thousands. You want your users to love it and tell everyone they know. The Android User Experience team is here to help. We talk about the Android Design guide and other tricks of the trade for creating apps that delight users and help them accomplish their goals. No design background is required.</p>
+  </div>
+  <div class="layout-content-col span-6">
+    <iframe width="355" height="200" src="http://www.youtube.com/embed/2NL_83EG0no" frameborder="0" allowfullscreen=""></iframe>
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-7">
+    <h3 id="design-for-engineers"><a href="https://developers.google.com/events/io/sessions/gooio2012/1204/">Android Design for Engineers</a></h3>
+    <p>Design isn't black magic, it's a field that people can learn. In this talk two elite designers from Google give you an advanced crash course in interactive and visual design. Topics include mental models, natural mappings, metaphors, mode errors, visual hierarchies, typography and gestalt principles. Correctly applied, this knowledge can drastically improve the quality of your work.</p>
+  </div>
+  <div class="layout-content-col span-6">
+    <iframe width="355" height="200" src="http://www.youtube.com/embed/iJDoxOTyMdk" frameborder="0" allowfullscreen=""></iframe>
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-7">
+    <h3 id="navigation-in-android"><a href="https://developers.google.com/events/io/sessions/gooio2012/114/">Navigation in Android</a></h3>
+    <p>An app is useless if people can't find their way around it. Android introduced big navigation-support changes in 3.0 and 4.0. The Action Bar offers a convenient control for Up navigation, the Back key's behavior became more consistent within tasks, and the Recent Tasks UI got an overhaul. In this talk, we discuss how and why we got where we are today, how to think about navigation when designing your app's user experience, and how to write apps that offer effortless navigation in multiple Android versions.</p>
+  </div>
+  <div class="layout-content-col span-6">
+    <iframe width="355" height="200" src="http://www.youtube.com/embed/XwGHJJYBs0Q" frameborder="0" allowfullscreen=""></iframe>
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-7">
+    <h3 id="now-what"><a href="https://developers.google.com/events/io/sessions/gooio2012/115/">So You've Read the Design Guide&#59; Now What?</a></h3>
+    <p>The Android Design Guide describes how to design beautiful Android apps, but not how to build them. In this talk we give practical tips for how to apply fit &amp; finish as you implement your design, we show you how to avoid some common pitfalls, we describe some useful patterns, and show how tools can help.</p>
+  </div>
+  <div class="layout-content-col span-6">
+    <iframe width="355" height="200" src="http://www.youtube.com/embed/2jCVmfCse1E" frameborder="0" allowfullscreen=""></iframe>
+  </div>
+</div>
+
+<div class="vspace size-2">&nbsp;</div>
+
+<div class="layout-content-row">
+  <div class="layout-content-col span-7">
+    <h3 id="playing-with-patterns"><a href="https://developers.google.com/events/io/sessions/gooio2012/131/">Playing with Patterns</a></h3>
+    <p>Best-in-class application designers and developers talk about their experience in developing for Android, showing screenshots from their app, exploring the challenges they faced, and offering creative solutions congruent with the Android Design guide. Guests are invited to show examples of visual and interaction patterns in their application that manage to keep it simultaneously consistent and personal.</p>
+  </div>
+  <div class="layout-content-col span-6">
+    <iframe width="355" height="200" src="http://www.youtube.com/embed/8iUbr8RZKtg" frameborder="0" allowfullscreen=""></iframe>
+  </div>
+</div>
+
+<p>Videos for the entire Design Track can also be found on the <a href="http://www.youtube.com/playlist?list=PL54FA004D676C3EE9">Android Developers Channel</a> on YouTube.</p>
diff --git a/docs/html/develop/index.jd b/docs/html/develop/index.jd
index eaa70e2..14ab5d5 100644
--- a/docs/html/develop/index.jd
+++ b/docs/html/develop/index.jd
@@ -180,7 +180,6 @@
 </div>
 
 <br class="clearfix"/>
-    </div>
 
       
       
diff --git a/docs/html/guide/practices/security.jd b/docs/html/guide/practices/security.jd
index ce59a9d..36eeff8 100644
--- a/docs/html/guide/practices/security.jd
+++ b/docs/html/guide/practices/security.jd
@@ -1,11 +1,11 @@
-page.title=Designing for Security
+page.title=Designing for Security
 @jd:body
 
 <div id="qv-wrapper">
 <div id="qv">
 <h2>In this document</h2>
 <ol>
-<li><a href="#Dalvik">Using Davlik Code</a></li>
+<li><a href="#Dalvik">Using Dalvik Code</a></li>
 <li><a href="#Native">Using Native Code</a></li>
 <li><a href="#Data">Storing Data</a></li>
 <li><a href="#IPC">Using IPC</a></li>
diff --git a/docs/html/guide/topics/media/camera.jd b/docs/html/guide/topics/media/camera.jd
index a63270a..3fe23f8 100644
--- a/docs/html/guide/topics/media/camera.jd
+++ b/docs/html/guide/topics/media/camera.jd
@@ -617,7 +617,7 @@
 
         // Create our Preview view and set it as the content of our activity.
         mPreview = new CameraPreview(this, mCamera);
-        FrameLayout preview = (FrameLayout) findViewById(id.camera_preview);
+        FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
         preview.addView(mPreview);
     }
 }
diff --git a/docs/html/guide/topics/providers/content-provider-basics.jd b/docs/html/guide/topics/providers/content-provider-basics.jd
index 8c47ad7..527e713 100644
--- a/docs/html/guide/topics/providers/content-provider-basics.jd
+++ b/docs/html/guide/topics/providers/content-provider-basics.jd
@@ -2,9 +2,7 @@
 @jd:body
 <div id="qv-wrapper">
 <div id="qv">
-
-
-                    <!-- In this document -->
+<!-- In this document -->
 <h2>In this document</h2>
 <ol>
     <li>
@@ -238,15 +236,11 @@
 </p>
 <p>
     For example, to get a list of the words and their locales from the User Dictionary Provider,
-    you call {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
-    ContentResolver.query()}.
-    The {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
-    query()} method calls the
-    {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
-    ContentProvider.query()} method defined by the User Dictionary Provider. The following lines
-    of code show a
-    {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
-    ContentResolver.query()} call:
+    you call {@link android.content.ContentResolver#query ContentResolver.query()}.
+    The {@link android.content.ContentResolver#query query()} method calls the
+    {@link android.content.ContentProvider#query ContentProvider.query()} method defined by the 
+    User Dictionary Provider. The following lines of code show a
+    {@link android.content.ContentResolver#query ContentResolver.query()} call:
 <p>
 <pre>
 // Queries the user dictionary and returns results
@@ -259,7 +253,7 @@
 </pre>
 <p>
     Table 2 shows how the arguments to
-    {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+    {@link android.content.ContentResolver#query 
     query(Uri,projection,selection,selectionArgs,sortOrder)} match an SQL SELECT statement:
 </p>
 <p class="table-caption">
@@ -344,7 +338,7 @@
     <code>4</code> from user dictionary, you can use this content URI:
 </p>
 <pre>
-Uri singleUri = ContentUri.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
+Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
 </pre>
 <p>
     You often use id values when you've retrieved a set of rows and then want to update or delete
@@ -354,7 +348,7 @@
     <strong>Note:</strong> The {@link android.net.Uri} and {@link android.net.Uri.Builder} classes
     contain convenience methods for constructing well-formed Uri objects from strings. The
     {@link android.content.ContentUris} contains convenience methods for appending id values to
-    a URI. The previous snippet uses {@link android.content.ContentUris#withAppendedId(Uri, long)
+    a URI. The previous snippet uses {@link android.content.ContentUris#withAppendedId
     withAppendedId()} to append an id to the UserDictionary content URI.
 </p>
 
@@ -367,10 +361,9 @@
 </p>
 <p class="note">
     For the sake of clarity, the code snippets in this section call
-    {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
-    ContentResolver.query()} on the "UI thread"". In actual code, however, you should
-    do queries asynchronously on a separate thread. One way to do this is to use the
-    {@link android.content.CursorLoader} class, which is described
+    {@link android.content.ContentResolver#query ContentResolver.query()} on the "UI thread"". In 
+    actual code, however, you should do queries asynchronously on a separate thread. One way to do 
+    this is to use the {@link android.content.CursorLoader} class, which is described
     in more detail in the <a href="{@docRoot}guide/components/loaders.html">
     Loaders</a> guide. Also, the lines of code are snippets only; they don't show a complete
     application.
@@ -391,8 +384,8 @@
     To retrieve data from a provider, your application needs "read access permission" for the
     provider. You can't request this permission at run-time; instead, you have to specify that
     you need this permission in your manifest, using the
-    <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
-    &lt;uses-permission&gt;</a></code> element and the exact permission name defined by the
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+    element and the exact permission name defined by the
     provider. When you specify this element in your manifest, you are in effect "requesting" this
     permission for your application. When users install your application, they implicitly grant
     this request.
@@ -436,10 +429,9 @@
 </pre>
 <p>
     The next snippet shows how to use
-    {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
-    ContentResolver.query()}, using the User Dictionary Provider as an example.
-    A provider client query is similar to an SQL query, and it contains a set of columns to return,
-    a set of selection criteria, and a sort order.
+    {@link android.content.ContentResolver#query ContentResolver.query()}, using the User Dictionary
+    Provider as an example. A provider client query is similar to an SQL query, and it contains a 
+    set of columns to return, a set of selection criteria, and a sort order.
 </p>
 <p>
     The set of columns that the query should return is called a <strong>projection</strong>
@@ -448,9 +440,9 @@
 <p>
     The expression that specifies the rows to retrieve is split into a selection clause and
     selection arguments. The selection clause is a combination of logical and Boolean expressions,
-    column names, and values (the variable <code>mSelection</code>). If you specify the replaceable
-    parameter <code>?</code> instead of a value, the query method retrieves the value from the
-    selection arguments array (the variable <code>mSelectionArgs</code>).
+    column names, and values (the variable <code>mSelectionClause</code>). If you specify the 
+    replaceable parameter <code>?</code> instead of a value, the query method retrieves the value 
+    from the selection arguments array (the variable <code>mSelectionArgs</code>).
 </p>
 <p>
     In the next snippet, if the user doesn't enter a word, the selection clause is set to
@@ -517,7 +509,7 @@
     This query is analogous to the SQL statement:
 </p>
 <pre>
-SELECT _ID, word, frequency, locale FROM words WHERE word = &lt;userinput&gt; ORDER BY word ASC;
+SELECT _ID, word, locale FROM words WHERE word = &lt;userinput&gt; ORDER BY word ASC;
 </pre>
 <p>
     In this SQL statement, the actual column names are used instead of contract class constants.
@@ -575,16 +567,15 @@
 <!-- Displaying the results -->
 <h3 id="DisplayResults">Displaying query results</h3>
 <p>
-    The {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
-    ContentResolver.query()} client method always returns a {@link android.database.Cursor}
-    containing the columns specified by the query's projection for the rows that match the query's
-    selection criteria. A {@link android.database.Cursor} object provides random read access to the
-    rows and columns it contains. Using {@link android.database.Cursor} methods,
-    you can iterate over the rows in the results, determine the data type of each column, get the
-    data out of a column, and examine other properties of the results. Some
-    {@link android.database.Cursor} implementations automatically update the object when the
-    provider's data changes, or trigger methods in an observer object when the
-    {@link android.database.Cursor} changes, or both.
+    The {@link android.content.ContentResolver#query ContentResolver.query()} client method always 
+    returns a {@link android.database.Cursor} containing the columns specified by the query's 
+    projection for the rows that match the query's selection criteria. A 
+    {@link android.database.Cursor} object provides random read access to the rows and columns it 
+    contains. Using {@link android.database.Cursor} methods, you can iterate over the rows in the 
+    results, determine the data type of each column, get the data out of a column, and examine other
+    properties of the results. Some {@link android.database.Cursor} implementations automatically 
+    update the object when the provider's data changes, or trigger methods in an observer object 
+    when the {@link android.database.Cursor} changes, or both.
 </p>
 <p class="note">
     <strong>Note:</strong> A provider may restrict access to columns based on the nature of the
@@ -594,7 +585,7 @@
 <p>
     If no rows match the selection criteria, the provider
     returns a {@link android.database.Cursor} object for which
-    {@link android.database.Cursor#getCount() Cursor.getCount()} is 0 (an empty cursor).
+    {@link android.database.Cursor#getCount Cursor.getCount()} is 0 (an empty cursor).
 </p>
 <p>
     If an internal error occurs, the results of the query depend on the particular provider. It may
@@ -685,8 +676,8 @@
 <p>
     {@link android.database.Cursor} implementations contain several "get" methods for
     retrieving different types of data from the object. For example, the previous snippet
-    uses {@link android.database.Cursor#getString(int) getString()}. They also have a
-    {@link android.database.Cursor#getType(int) getType()} method that returns a value indicating
+    uses {@link android.database.Cursor#getString getString()}. They also have a
+    {@link android.database.Cursor#getType getType()} method that returns a value indicating
     the data type of the column.
 </p>
 
@@ -713,17 +704,16 @@
 </p>
 <p>
     To get the permissions needed to access a provider, an application requests them with a
-    <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
-    &lt;uses-permission&gt;</a></code> element in its manifest file.
-    When the Android Package Manager installs the application, a user must approve all of the
-    permissions the application requests. If the user approves all of them, Package Manager
-    continues the installation; if the user doesn't approve them, Package Manager
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code>
+    element in its manifest file. When the Android Package Manager installs the application, a user 
+    must approve all of the permissions the application requests. If the user approves all of them, 
+    Package Manager continues the installation; if the user doesn't approve them, Package Manager
     aborts the installation.
 </p>
 <p>
     The following
-    <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
-    &lt;uses-permission&gt;</a></code> element requests read access to the User Dictionary Provider:
+<code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">&lt;uses-permission&gt;</a></code> 
+    element requests read access to the User Dictionary Provider:
 </p>
 <pre>
     &lt;uses-permission android:name="android.permission.READ_USER_DICTIONARY"&gt;
@@ -746,7 +736,7 @@
 <h3 id="Inserting">Inserting data</h3>
 <p>
     To insert data into a provider, you call the
-    {@link android.content.ContentResolver#insert(Uri,ContentValues) ContentResolver.insert()}
+    {@link android.content.ContentResolver#insert ContentResolver.insert()}
     method. This method inserts a new row into the provider and returns a content URI for that row.
     This snippet shows how to insert a new word into the User Dictionary Provider:
 </p>
@@ -777,8 +767,7 @@
     The data for the new row goes into a single {@link android.content.ContentValues} object, which
     is similar in form to a one-row cursor. The columns in this object don't need to have the
     same data type, and if you don't want to specify a value at all, you can set a column
-    to <code>null</code> using {@link android.content.ContentValues#putNull(String)
-    ContentValues.putNull()}.
+    to <code>null</code> using {@link android.content.ContentValues#putNull ContentValues.putNull()}.
 </p>
 <p>
     The snippet doesn't add the <code>_ID</code> column, because this column is maintained
@@ -799,17 +788,16 @@
 </p>
 <p>
     To get the value of <code>_ID</code> from the returned {@link android.net.Uri}, call
-    {@link android.content.ContentUris#parseId(Uri) ContentUris.parseId()}.
+    {@link android.content.ContentUris#parseId ContentUris.parseId()}.
 </p>
 <h3 id="Updating">Updating data</h3>
 <p>
     To update a row, you use a {@link android.content.ContentValues} object with the updated
     values just as you do with an insertion, and selection criteria just as you do with a query.
     The client method you use is
-    {@link android.content.ContentResolver#update(Uri, ContentValues, String, String[])
-    ContentResolver.update()}. You only need to add values to the
-    {@link android.content.ContentValues} object for columns you're updating. If you want to clear
-    the contents of a column, set the value to <code>null</code>.
+    {@link android.content.ContentResolver#update ContentResolver.update()}. You only need to add 
+    values to the {@link android.content.ContentValues} object for columns you're updating. If you 
+    want to clear the contents of a column, set the value to <code>null</code>.
 </p>
 <p>
     The following snippet changes all the rows whose locale has the language "en" to a
@@ -842,9 +830,8 @@
 </pre>
 <p>
     You should also sanitize user input when you call
-    {@link android.content.ContentResolver#update(Uri, ContentValues, String, String[])
-    ContentResolver.update()}. To learn more about this, read the section
-    <a href="#Injection">Protecting against malicious input</a>.
+    {@link android.content.ContentResolver#update ContentResolver.update()}. To learn more about 
+    this, read the section <a href="#Injection">Protecting against malicious input</a>.
 </p>
 <h3 id="Deleting">Deleting data</h3>
 <p>
@@ -873,9 +860,8 @@
 </pre>
 <p>
     You should also sanitize user input when you call
-    {@link android.content.ContentResolver#delete(Uri, String, String[])
-    ContentResolver.delete()}. To learn more about this, read the section
-    <a href="#Injection">Protecting against malicious input</a>.
+    {@link android.content.ContentResolver#delete ContentResolver.delete()}. To learn more about 
+    this, read the section <a href="#Injection">Protecting against malicious input</a>.
 </p>
 <!-- Provider Data Types -->
 <h2 id="DataTypes">Provider Data Types</h2>
@@ -907,7 +893,7 @@
     The data types for the User Dictionary Provider are listed in the reference documentation
     for its contract class {@link android.provider.UserDictionary.Words} (contract classes are
     described in the section <a href="#ContractClasses">Contract Classes</a>).
-    You can also determine the data type by calling {@link android.database.Cursor#getType(int)
+    You can also determine the data type by calling {@link android.database.Cursor#getType
     Cursor.getType()}.
 </p>
 <p>
@@ -918,7 +904,7 @@
     data structures or files. For example, the {@link android.provider.ContactsContract.Data}
     table in the Contacts Provider uses MIME types to label the type of contact data stored in each
     row. To get the MIME type corresponding to a content URI, call
-    {@link android.content.ContentResolver#getType(Uri) ContentResolver.getType()}.
+    {@link android.content.ContentResolver#getType ContentResolver.getType()}.
 </p>
 <p>
     The section <a href="#MIMETypeReference">MIME Type Reference</a> describes the
@@ -935,8 +921,7 @@
     <li>
         <a href="#Batch">Batch access</a>: You can create a batch of access calls with methods in
         the {@link android.content.ContentProviderOperation} class, and then apply them with
-        {@link android.content.ContentResolver#applyBatch(String, ArrayList)
-        ContentResolver.applyBatch()}.
+        {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}.
     </li>
     <li>
         Asynchronous queries: You should do queries in a separate thread. One way to do this is to
@@ -963,11 +948,10 @@
     To access a provider in "batch mode",
     you create an array of {@link android.content.ContentProviderOperation} objects and then
     dispatch them to a content provider with
-    {@link android.content.ContentResolver#applyBatch(String, ArrayList)
-    ContentResolver.applyBatch()}. You pass the content provider's <em>authority</em> to this
-    method, rather than a particular content URI, which allows each
-    {@link android.content.ContentProviderOperation} object in the array to work against a
-    different table. A call to {@link android.content.ContentResolver#applyBatch(String, ArrayList)
+    {@link android.content.ContentResolver#applyBatch ContentResolver.applyBatch()}. You pass the 
+    content provider's <em>authority</em> to this  method, rather than a particular content URI. 
+    This allows each {@link android.content.ContentProviderOperation} object in the array to work 
+    against a different table. A call to {@link android.content.ContentResolver#applyBatch
     ContentResolver.applyBatch()} returns an array of results.
 </p>
 <p>
@@ -1028,14 +1012,13 @@
 </p>
 <p>
     A provider defines URI permissions for content URIs in its manifest, using the
-    <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
-    android:grantUriPermission</a></code>
-    attribute of the <a href="{@docRoot}guide/topics/manifest/provider-element.html">
-    {@code &lt;provider&gt;}</a>
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">android:grantUriPermission</a></code>
+    attribute of the 
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
     element, as well as the
-    <a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">{@code 
-    &lt;grant-uri-permission&gt;}</a> child element of the
-    <a href="{@docRoot}guide/topics/manifest/provider-element.html">{@code &lt;provider&gt;}</a>
+<code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">&lt;grant-uri-permission&gt;</a></code>
+    child element of the
+<code><a href="{@docRoot}guide/topics/manifest/provider-element.html">&lt;provider&gt;</a></code>
     element. The URI permissions mechanism is explained in more detail in the
     <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a> guide,
     in the section "URI Permissions".
@@ -1053,7 +1036,7 @@
         Your application sends an intent containing the action
         {@link android.content.Intent#ACTION_PICK} and the "contacts" MIME type
         {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE}, using the
-        method {@link android.app.Activity#startActivityForResult(Intent, int)
+        method {@link android.app.Activity#startActivityForResult
         startActivityForResult()}.
     </li>
     <li>
@@ -1063,7 +1046,7 @@
     <li>
         In the selection activity, the user selects a
         contact to update. When this happens, the selection activity calls
-        {@link android.app.Activity#setResult(int, Intent) setResult(resultcode, intent)}
+        {@link android.app.Activity#setResult setResult(resultcode, intent)}
         to set up a intent to give back to your application. The intent contains the content URI
         of the contact the user selected, and the "extras" flags
         {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}. These flags grant URI
@@ -1073,7 +1056,7 @@
     </li>
     <li>
         Your activity returns to the foreground, and the system calls your activity's
-        {@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()}
+        {@link android.app.Activity#onActivityResult onActivityResult()}
         method. This method receives the result intent created by the selection activity in
         the People app.
     </li>
diff --git a/docs/html/guide/topics/search/index.jd b/docs/html/guide/topics/search/index.jd
index 2ee624b..680c607 100644
--- a/docs/html/guide/topics/search/index.jd
+++ b/docs/html/guide/topics/search/index.jd
@@ -54,9 +54,9 @@
 if your data is stored in an SQLite database, you should use the {@link android.database.sqlite}
 APIs to perform searches.
 <br/><br/>
-Also, there is no guarantee that every device provides a dedicated SEARCH button to invoke the
+Also, there is no guarantee that a device provides a dedicated SEARCH button that invokes the
 search interface in your application. When using the search dialog or a custom interface, you
-must always provide a search button in your UI that activates the search interface. For more
+must provide a search button in your UI that activates the search interface. For more
 information, see <a href="search-dialog.html#InvokingTheSearchDialog">Invoking the search
 dialog</a>.</p>
 
diff --git a/docs/html/guide/topics/search/search-dialog.jd b/docs/html/guide/topics/search/search-dialog.jd
index 49451ac..b9a26d6 100644
--- a/docs/html/guide/topics/search/search-dialog.jd
+++ b/docs/html/guide/topics/search/search-dialog.jd
@@ -6,14 +6,6 @@
 <div id="qv-wrapper">
 <div id="qv">
 
-  <h2>Quickview</h2>
-  <ul>
-    <li>The Android system sends search queries from the search dialog or widget to an activity you
-specify to perform searches and present results</li>
-    <li>You can put the search widget in the Action Bar, as an "action view," for quick
-access</li>
-  </ul>
-
 
 <h2>In this document</h2>
 <ol>
@@ -61,14 +53,8 @@
 
 <h2>Downloads</h2>
 <ol>
-<li><a href="{@docRoot}shareables/search_icons.zip">search_icons.zip</a></li>
-</ol>
-
-<h2>See also</h2>
-<ol>
-<li><a href="adding-recent-query-suggestions.html">Adding Recent Query Suggestions</a></li>
-<li><a href="adding-custom-suggestions.html">Adding Custom Suggestions</a></li>
-<li><a href="searchable-config.html">Searchable Configuration</a></li>
+<li><a href="{@docRoot}design/downloads/index.html#action-bar-icon-pack">Action Bar
+Icon Pack</a></li>
 </ol>
 
 </div>
@@ -142,12 +128,14 @@
   <li>A search interface, provided by either:
     <ul>
       <li>The search dialog
-        <p>By default, the search dialog is hidden, but appears at the top of the screen when the 
-user presses the device SEARCH button (when available) or another button in your user interface.</p>
+        <p>By default, the search dialog is hidden, but appears at the top of the screen when
+          you call {@link android.app.Activity#onSearchRequested()} (when the user presses your
+          Search button).</p>
       </li>
       <li>Or, a {@link android.widget.SearchView} widget
         <p>Using the search widget allows you to put the search box anywhere in your activity.
-Instead of putting it in your activity layout, however, it's usually more convenient for users as an
+Instead of putting it in your activity layout, you should usually use
+{@link android.widget.SearchView} as an 
 <a href="{@docRoot}guide/topics/ui/actionbar.html#ActionView">action view in the Action Bar</a>.</p>
       </li>
     </ul>
@@ -415,10 +403,9 @@
 your application for devices running Android 3.0, you should consider using the search widget
 instead (see the side box).</p>
 
-<p>The search dialog is always hidden by default, until the user activates it. If the user's device
-includes a SEARCH button, pressing it will activate the search dialog by default. Your application
-can also activate the search dialog on demand by calling {@link
-android.app.Activity#onSearchRequested onSearchRequested()}. However, neither of these work
+<p>The search dialog is always hidden by default, until the user activates it. Your application
+can activate the search dialog by calling {@link
+android.app.Activity#onSearchRequested onSearchRequested()}. However, this method doesn't work
 until you enable the search dialog for the activity.</p>
 
 <p>To enable the search dialog, you must indicate to the system which searchable activity should
@@ -469,8 +456,8 @@
 href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code &lt;meta-data&gt;}</a>
 element to declare which searchable activity to use for searches, the activity has enabled the
 search dialog.
-While the user is in this activity, the device SEARCH button (if available) and the {@link
-android.app.Activity#onSearchRequested onSearchRequested()} method will activate the search dialog.
+While the user is in this activity, the {@link
+android.app.Activity#onSearchRequested onSearchRequested()} method activates the search dialog.
 When the user executes the search, the system starts {@code SearchableActivity} and delivers it
 the {@link android.content.Intent#ACTION_SEARCH} intent.</p>
 
@@ -495,21 +482,22 @@
 
 <h3 id="InvokingTheSearchDialog">Invoking the search dialog</h3>
 
-<p>As mentioned above, the device SEARCH button will open the search dialog as long as the current
-activity has declared in the manifest the searchable activity to use.</p>
+<p>Although some devices provide a dedicated Search button, the behavior of the button may vary
+between devices and many devices do not provide a Search button at all. So when using the search
+dialog, you <strong>must provide a search button in your UI</strong> that activates the search
+dialog by calling {@link android.app.Activity#onSearchRequested()}.</p>
 
-<p>However, some devices do not include a dedicated SEARCH button, so you should not assume that
-it's always available. When using the search dialog, you must <strong>always provide another search
-button in your UI</strong> that activates the search dialog by calling {@link
-android.app.Activity#onSearchRequested()}.</p>
+<p>For instance, you should add a Search button in your <a
+href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options Menu</a> or UI
+layout that calls {@link android.app.Activity#onSearchRequested()}. For consistency with
+the Android system and other apps, you should label your button with the Android Search icon that's
+available from the <a href="{@docRoot}design/downloads/index.html#action-bar-icon-pack">Action Bar
+Icon Pack</a>.</p>
 
-<p>For instance, you should either provide a menu item in your <a
-href="{@docRoot}guide/topics/ui/menus.html#options-menu">Options Menu</a> or a button in your
-activity layout that
-activates search by calling {@link android.app.Activity#onSearchRequested()}. The <a
-href="{@docRoot}shareables/search_icons.zip">search_icons.zip</a> file includes icons for
-medium and high density screens, which you can use for your search menu item or button (low-density
-screens scale-down the hdpi image by one half). </p>
+<p class="note"><strong>Note:</strong> If your app uses the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>, then you should not use
+the search dialog for your search interface. Instead, use the <a href="#UsingSearchWidget">search
+widget</a> as a collapsible view in the action bar.</p>
 
 <p>You can also enable "type-to-search" functionality, which activates the search dialog when the
 user starts typing on the keyboard&mdash;the keystrokes are inserted into the search dialog. You can
diff --git a/docs/html/guide/topics/ui/controls/radiobutton.jd b/docs/html/guide/topics/ui/controls/radiobutton.jd
index f6f6d49..c96e576 100644
--- a/docs/html/guide/topics/ui/controls/radiobutton.jd
+++ b/docs/html/guide/topics/ui/controls/radiobutton.jd
@@ -72,7 +72,7 @@
 <pre>
 public void onRadioButtonClicked(View view) {
     // Is the button now checked?
-    boolean checked = (RadioButton) view).isChecked();
+    boolean checked = ((RadioButton) view).isChecked();
     
     // Check which radio button was clicked
     switch(view.getId()) {
diff --git a/docs/html/guide/topics/ui/declaring-layout.jd b/docs/html/guide/topics/ui/declaring-layout.jd
index e971a75..e229f23 100644
--- a/docs/html/guide/topics/ui/declaring-layout.jd
+++ b/docs/html/guide/topics/ui/declaring-layout.jd
@@ -32,12 +32,17 @@
     <li>{@link android.view.ViewGroup}</li>
     <li>{@link android.view.ViewGroup.LayoutParams}</li>
   </ol>
-</div>
+  
+  <h2>See also</h2>
+  <ol>
+    <li><a href="{@docRoot}training/basics/firstapp/building-ui.html">Building a Simple User
+Interface</a></li> </div>
 </div>
 
-<p>Your layout is the architecture for the user interface in an Activity.
-It defines the layout structure and holds all the elements that appear to the user. 
-You can declare your layout in two ways:</p>
+<p>A layout defines the visual structure for a user interface, such as the UI for an <a
+href="{@docRoot}guide/components/activities.html">activity</a> or <a
+href="{@docRoot}guide/topics/appwidgets/index.html">app widget</a>.
+You can declare a layout in two ways:</p>
 <ul>
 <li><strong>Declare UI elements in XML</strong>. Android provides a straightforward XML 
 vocabulary that corresponds to the View classes and subclasses, such as those for widgets and layouts.</li>
@@ -77,16 +82,6 @@
 
 <h2 id="write">Write the XML</h2>
 
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<p>For your convenience, the API reference documentation for UI related classes
-lists the available XML attributes that correspond to the class methods, including inherited
-attributes.</p>
-<p>To learn more about the available XML elements and attributes, as well as the format of the XML file, see <a
-href="{@docRoot}guide/topics/resources/available-resources.html#layoutresources">Layout Resources</a>.</p>
-</div>
-</div>
-
 <p>Using Android's XML vocabulary, you can quickly design UI layouts and the screen elements they contain, in the same way you create web pages in HTML &mdash; with a series of nested elements. </p>
 
 <p>Each layout file must contain exactly one root element, which must be a View or ViewGroup object. Once you've defined the root element, you can add additional layout objects or widgets as child elements to gradually build a View hierarchy that defines your layout. For example, here's an XML layout that uses a vertical {@link android.widget.LinearLayout}
@@ -111,7 +106,8 @@
 <p>After you've declared your layout in XML, save the file with the <code>.xml</code> extension, 
 in your Android project's <code>res/layout/</code> directory, so it will properly compile. </p>
 
-<p>We'll discuss each of the attributes shown here a little later.</p>
+<p>More information about the syntax for a layout XML file is available in the <a
+href="{@docRoot}guide/topics/resources/layout-resource.html">Layout Resources</a> document.</p>
 
 <h2 id="load">Load the XML Resource</h2>
 
diff --git a/docs/html/guide/topics/ui/layout/gridview.jd b/docs/html/guide/topics/ui/layout/gridview.jd
index 11c5474..67bdd0f0 100644
--- a/docs/html/guide/topics/ui/layout/gridview.jd
+++ b/docs/html/guide/topics/ui/layout/gridview.jd
@@ -22,10 +22,15 @@
 scrollable grid. The grid items are automatically inserted to the layout using a {@link
 android.widget.ListAdapter}.</p>
 
+<p>For an introduction to how you can dynamically insert views using an adapter, read
+<a href="{@docRoot}guide/topics/ui/declaring-layout.html#AdapterViews">Building Layouts with
+  an Adapter</a>.</p>
+
 <img src="{@docRoot}images/ui/gridview.png" alt="" />
 
 
 <h2 id="example">Example</h2>
+
 <p>In this tutorial, you'll create a grid of image thumbnails. When an item is selected, a
 toast message will display the position of the image.</p>
 
diff --git a/docs/html/guide/topics/ui/layout/listview.jd b/docs/html/guide/topics/ui/layout/listview.jd
index 26a7597..fee5292 100644
--- a/docs/html/guide/topics/ui/layout/listview.jd
+++ b/docs/html/guide/topics/ui/layout/listview.jd
@@ -28,6 +28,10 @@
 android.widget.Adapter} that pulls content from a source such as an array or database query and
 converts each item result into a view that's placed into the list.</p>
 
+<p>For an introduction to how you can dynamically insert views using an adapter, read
+<a href="{@docRoot}guide/topics/ui/declaring-layout.html#AdapterViews">Building Layouts with
+  an Adapter</a>.</p>
+
 <img src="{@docRoot}images/ui/listview.png" alt="" />
 
 <h2 id="Loader">Using a Loader</h2>
@@ -147,5 +151,5 @@
 Provider</a>, if you want to
 try this code, your app must request the {@link android.Manifest.permission#READ_CONTACTS}
 permission in the manifest file:<br/>
-<code>&lt;uses-permission android:name="android.permission.READ_CONTACTS" /></p>
+<code>&lt;uses-permission android:name="android.permission.READ_CONTACTS" /></code></p>
 
diff --git a/docs/html/guide/topics/ui/settings.jd b/docs/html/guide/topics/ui/settings.jd
index fd3b684..33e164b 100644
--- a/docs/html/guide/topics/ui/settings.jd
+++ b/docs/html/guide/topics/ui/settings.jd
@@ -217,7 +217,7 @@
         android:dialogTitle="@string/pref_syncConnectionType"
         android:entries="@array/pref_syncConnectionTypes_entries"
         android:entryValues="@array/pref_syncConnectionTypes_values"
-        android:defaultValue="@string/pref_syncConnectionTypes_default" >
+        android:defaultValue="@string/pref_syncConnectionTypes_default" />
 &lt;/PreferenceScreen>
 </pre>
 
diff --git a/docs/html/intl/ja/index.jd b/docs/html/intl/ja/index.jd
deleted file mode 100644
index ac36f90..0000000
--- a/docs/html/intl/ja/index.jd
+++ /dev/null
@@ -1,159 +0,0 @@
-home=true
-@jd:body
-
-
-	<div id="mainBodyFixed">
-              <div id="mainBodyLeft">			
-                    <div id="homeMiddle">
-                        <div id="topAnnouncement">
-                            <div id="homeTitle">
-                                <h2>デベロッパーへのお知らせ</h2>
-                            </div><!-- end homeTitle -->
-                            <div id="announcement-block">
-                            <!-- total max width is 520px -->
-                                <img src="/assets/images/home/android_adc.png" alt="Android Developer Challenge 2" width="232px" />
-                                <div id="announcement" style="width:275px">
-                                  <p>第2Android Developer Challengeが、遂に登場しました!このアプリケーション開発コンテストでは、Androidのユーザなら誰でも簡単に参加でき、一等の賞金は$250,000 です。登録の締切日は8月31日になります。</p>
-                                  <p><a href="http://code.google.com/android/adc/">Android  Developer Challengeについて詳しくはこちら &raquo;</a></p>
-                                </div> <!-- end annoucement -->
-                            </div> <!-- end annoucement-block -->  
-                        </div><!-- end topAnnouncement -->
-                        <div id="carouselMain" style="height:210px"> <!-- this height can be adjusted based on the content height -->
-                        </div>
-                            <div class="clearer"></div>
-                        <div id="carouselWheel">
-                            <div class="app-list-container" align="center"> 
-                                <a href="javascript:{}" id="arrow-left" onclick="" class="arrow-left-off"></a>
-                                <div id="list-clip">
-                                    <div style="left: 0px;" id="app-list">
-                                      <!-- populated by buildCarousel() -->
-                                    </div>
-                                </div><!-- end list-clip -->
-                                <a href="javascript:{ page_right(); }" id="arrow-right" onclick="" class="arrow-right-on"></a>
-                                <div class="clearer"></div>
-                            </div><!-- end app-list container -->
-                        </div><!-- end carouselWheel -->
-                    </div><!-- end homeMiddle -->
-
-                    <div style="clear:both">&nbsp;</div>
-              </div><!-- end mainBodyLeft -->
-
-              <div id="mainBodyRight">
-                      <table id="rightColumn">
-                              <tr>
-                                      <td class="imageCell"><a href="{@docRoot}sdk/index.html"><img src="{@docRoot}assets/images/icon_download.jpg" style="padding:0" /></a></td>
-                                      <td>
-                                              <h2 class="green">ダウンロード</h2>
-                                              <p>Android SDK には、優れたアプリケーションの作成に必要となるツール、サンプル コード、ドキュメントが含まれています。  </p>
-                                              <p><a href="{@docRoot}sdk/index.html">詳細 &raquo;</a></p>
-                                      </td>
-                              </tr>
-                              <tr>
-                                      <td colspan="2"><div class="seperator">&nbsp;</div></td>
-                              </tr>
-                              <tr>
-                                      <td class="imageCell"><a href="http://play.google.com/apps/publish"><img src="{@docRoot}assets/images/icon_play.png" style="padding:0" /></a></td>
-                                      <td>
-                                              <h2 class="green">公開</h2>
-                                              <p>Android マーケットは、アプリケーションを携帯端末に配信するためのオープン サービスです。</p>
-                                              <p><a href="http://play.google.com/apps/publish">詳細 &raquo;</a></p>
-                                      </td>
-                              </tr>
-                              <tr>
-                                      <td colspan="2"><div class="seperator">&nbsp;</div></td>
-                              </tr>
-                              <tr>
-                                      <td class="imageCell"><a href="http://source.android.com"><img src="{@docRoot}assets/images/icon_contribute.jpg" style="padding:0" /></a></td>
-                                      <td>
-                                              <h2 class="green">貢献</h2>
-                                              <p>Android オープンソース プロジェクトでは、プラットフォーム全体のソースコードを公開しています。</p>
-                                              <p><a href="http://source.android.com">詳細 &raquo;</a></p>
-                                      </td>
-                              </tr>
-                              <tr>
-                                      <td colspan="2"><div class="seperator">&nbsp;</div></td>
-                              </tr>
-                              <tr>
-                                      <td class="imageCell"><a href="http://www.youtube.com/user/androiddevelopers"><img src="{@docRoot}assets/images/video-droid.png" style="padding:0" /></a></td>
-                                      <td>
-                                              <h2 class="green">再生</h2>
-                                              <object width="150" height="140"><param name="movie" value="http://www.youtube.com/v/GARMe7Km_gk&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/GARMe7Km_gk&hl=en&fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="150" height="140"></embed></object>
-                                              <p style="margin-top:1em"><a href="{@docRoot}videos/index.html">その他の Android 動画 &raquo;</a></p>
-                                      </td>
-                              </tr>
-
-                      </table>
-              </div>
-	</div>
-
-<!--[if lte IE 6]>
-  <style>
-    #arrow-left {
-      margin:0 0 0 5px;
-    }
-    #arrow-right {
-      margin-left:0;
-    }
-    .app-list-container {
-      margin: 37px 0 0 23px;
-    }
-    div#list-clip { 
-      width:468px;
-    }
-  </style>
-<![endif]-->
-
-<script type="text/javascript">
-
-// * -- carousel dictionary -- * //
-  /* layout:  imgLeft, imgRight, imgTop
-     icon:    image for carousel entry. cropped (height:70px, width:90px)
-     name:    string for carousel entry
-     img:     image for bulletin post. cropped (height: 170, width:230px)
-     title:   header for bulletin (optional, insert "" value to skip
-     desc:    the bulletin post. must include html tags. 
-  */
-
-  var droidList = {
-    'sdk': {
-      'layout':"imgLeft",
-      'icon':"sdk-small.png",
-      'name':"Android 2.0",
-      'img':"eclair-android.png",
-      'title':"Android 2.0",
-      'desc': "<p>Android 2.0 の最新バージョンが公開されました。このリリースには Android 2.0 用の API、最新版デベロッパーツール、複数プラットフォーム(バージョン)サポート、そして Google API のアドオンが含まれています。</p><p><a href='{@docRoot}sdk/index.html'>Android SDK をダウンロード &raquo;</a></p>"
-    },
-    
-    'io': {
-      'layout':"imgLeft",
-      'icon':"io-small.png",
-      'name':"Google I/O",
-      'img':"io-large.png",
-      'title':"Google I/O Developer Conference",
-      'desc': "<p>Google I/O は、サンフランシスコの Moscone Center で 5 月 27~28 日に開催された開発者会議です。このイベントに参加できなかった方は、各アンドロイド向けセッションを、YouTube ビデオ資料で体験する事が可能<nobr>です</nobr>。</p><p><a href='{@docRoot}videos/index.html'>セッションを参照してください &raquo;</a></p>"
-    },
-
-    'mapskey': {
-      'layout':"imgLeft",
-      'icon':"maps-small.png",
-      'name':"Maps API キー",
-      'img':"maps-large.png",
-      'title':"Maps API キー",
-      'desc':"<p>MapView から Google マップを利用する Android アプリケーションを開発する場合は、アプリケーションを登録して Maps API キーを取得する必要があります。この API キーが無いアプリケーションは、Android 上で動作しません。キーの取得は、簡単な手順で行うことができます。</p><p><a href='http://code.google.com/android/add-ons/google-apis/maps-overview.html'>詳細 &raquo;</a></p>"
-    },
-
-    'devphone': {
-      'layout':"imgLeft",
-      'icon':"devphone-small.png",
-      'name':"Dev Phone 1",
-      'img':"devphone-large.png",
-      'title':"Android Dev Phone 1",
-      'desc': "<p>この携帯電話を使用することで、開発した Android アプリケーションの実行とデバッグを行うことができます。Android オペレーティングシステムを変更してからリビルドし、携帯電話に書き込むことができます。Android Dev Phone 1 は携帯通信会社に依存しておらず、<a href='http://play.google.com/apps/publish'>Android マーケット</a>に登録済みのデベロッパーなら誰でも購入可能です。</p><p><a href='/tools/device.html#dev-phone-1'>Android Dev Phone 1 の詳細&raquo;</a></p>"
-    }
-
-  }
-</script>
-<script type="text/javascript" src="{@docRoot}assets/carousel.js"></script>
-<script type="text/javascript">
-  initCarousel("sdk");
-</script>
diff --git a/docs/html/training/basics/activity-lifecycle/starting.jd b/docs/html/training/basics/activity-lifecycle/starting.jd
index 1a4bc2d..dd17304 100644
--- a/docs/html/training/basics/activity-lifecycle/starting.jd
+++ b/docs/html/training/basics/activity-lifecycle/starting.jd
@@ -112,7 +112,7 @@
 </table>
 -->
 
-<p>As you'll learn in the following lessons, there are several situtations in which an activity
+<p>As you'll learn in the following lessons, there are several situations in which an activity
 transitions between different states that are illustrated in figure 1. However, only three of
 these states can be static. That is, the activity can exist in one of only three states for an
 extended period of time:</p>
diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd
index 4d0a84a..3dafcfa 100644
--- a/docs/html/training/basics/firstapp/starting-activity.jd
+++ b/docs/html/training/basics/firstapp/starting-activity.jd
@@ -285,8 +285,8 @@
 
 <p>The app is now runnable because the {@link android.content.Intent} in the
 first activity now resolves to the {@code DisplayMessageActivity} class. If you run the app now,
-clicking the Send button starts the
-second activity, but it doesn't show anything yet.</p>
+clicking the Send button starts the second activity, but it's still using the default
+"Hello world" layout.</p>
 
 
 <h2 id="ReceiveIntent">Receive the Intent</h2>
diff --git a/drm/jni/Android.mk b/drm/jni/Android.mk
index f8ecc8c..fff7eee 100644
--- a/drm/jni/Android.mk
+++ b/drm/jni/Android.mk
@@ -35,7 +35,8 @@
     $(JNI_H_INCLUDE) \
     $(TOP)/frameworks/av/drm/libdrmframework/include \
     $(TOP)/frameworks/av/drm/libdrmframework/plugins/common/include \
-    $(TOP)/frameworks/av/include
+    $(TOP)/frameworks/av/include \
+    $(TOP)/libcore/include
 
 
 
diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp
index 1ee32fa..baddf62 100644
--- a/drm/jni/android_drm_DrmManagerClient.cpp
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -20,6 +20,7 @@
 
 #include <jni.h>
 #include <JNIHelp.h>
+#include <ScopedLocalRef.h>
 #include <android_runtime/AndroidRuntime.h>
 
 #include <drm/DrmInfo.h>
@@ -250,16 +251,18 @@
         = getDrmManagerClientImpl(env, thiz)->getConstraints(uniqueId, &pathString, usage);
 
     jclass localRef = env->FindClass("android/content/ContentValues");
+    jmethodID ContentValues_putByteArray =
+            env->GetMethodID(localRef, "put", "(Ljava/lang/String;[B)V");
+    jmethodID ContentValues_putString =
+            env->GetMethodID(localRef, "put", "(Ljava/lang/String;Ljava/lang/String;)V");
+    jmethodID ContentValues_constructor = env->GetMethodID(localRef, "<init>", "()V");
     jobject constraints = NULL;
 
     if (NULL != localRef && NULL != pConstraints) {
-        // Get the constructor id
-        jmethodID constructorId = env->GetMethodID(localRef, "<init>", "()V");
         // create the java DrmConstraints object
-        constraints = env->NewObject(localRef, constructorId);
+        constraints = env->NewObject(localRef, ContentValues_constructor);
 
         DrmConstraints::KeyIterator keyIt = pConstraints->keyIterator();
-
         while (keyIt.hasNext()) {
             String8 key = keyIt.next();
 
@@ -267,18 +270,18 @@
             if (DrmConstraints::EXTENDED_METADATA == key) {
                 const char* value = pConstraints->getAsByteArray(&key);
                 if (NULL != value) {
-                    jbyteArray dataArray = env->NewByteArray(strlen(value));
-                    env->SetByteArrayRegion(dataArray, 0, strlen(value), (jbyte*)value);
-                    env->CallVoidMethod(
-                        constraints, env->GetMethodID(localRef, "put", "(Ljava/lang/String;[B)V"),
-                                     env->NewStringUTF(key.string()), dataArray);
+                    ScopedLocalRef<jbyteArray> dataArray(env, env->NewByteArray(strlen(value)));
+                    ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
+                    env->SetByteArrayRegion(dataArray.get(), 0, strlen(value), (jbyte*)value);
+                    env->CallVoidMethod(constraints, ContentValues_putByteArray,
+                                        keyString.get(), dataArray.get());
                 }
             } else {
                 String8 value = pConstraints->get(key);
-                env->CallVoidMethod(
-                    constraints,
-                    env->GetMethodID(localRef, "put", "(Ljava/lang/String;Ljava/lang/String;)V"),
-                env->NewStringUTF(key.string()), env->NewStringUTF(value.string()));
+                ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
+                ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.string()));
+                env->CallVoidMethod(constraints, ContentValues_putString,
+                                    keyString.get(), valueString.get());
             }
         }
     }
@@ -297,8 +300,10 @@
 
     jobject metadata = NULL;
 
-    jclass localRef = NULL;
-    localRef = env->FindClass("android/content/ContentValues");
+    jclass localRef = env->FindClass("android/content/ContentValues");
+    jmethodID ContentValues_putString =
+            env->GetMethodID(localRef, "put", "(Ljava/lang/String;Ljava/lang/String;)V");
+
     if (NULL != localRef && NULL != pMetadata) {
         // Get the constructor id
         jmethodID constructorId = NULL;
@@ -313,9 +318,10 @@
                     // insert the entry<constraintKey, constraintValue>
                     // to newly created java object
                     String8 value = pMetadata->get(key);
-                    env->CallVoidMethod(metadata, env->GetMethodID(localRef, "put",
-                            "(Ljava/lang/String;Ljava/lang/String;)V"),
-                    env->NewStringUTF(key.string()), env->NewStringUTF(value.string()));
+                    ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
+                    ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.string()));
+                    env->CallVoidMethod(metadata, ContentValues_putString,
+                                        keyString.get(), valueString.get());
                 }
             }
         }
@@ -426,29 +432,30 @@
     DrmInfo drmInfo(mInfoType, buffer, mMimeType);
 
     jclass clazz = env->FindClass("android/drm/DrmInfo");
+    jmethodID DrmInfo_get = env->GetMethodID(clazz, "get", "(Ljava/lang/String;)Ljava/lang/Object;");
     jobject keyIterator
         = env->CallObjectMethod(drmInfoObject,
                 env->GetMethodID(clazz, "keyIterator", "()Ljava/util/Iterator;"));
 
-    jmethodID hasNextId = env->GetMethodID(env->FindClass("java/util/Iterator"), "hasNext", "()Z");
+    jclass Iterator_class = env->FindClass("java/util/Iterator");
+    jmethodID Iterator_hasNext = env->GetMethodID(Iterator_class, "hasNext", "()Z");
+    jmethodID Iterator_next = env->GetMethodID(Iterator_class, "next", "()Ljava/lang/Object;");
 
-    while (env->CallBooleanMethod(keyIterator, hasNextId)) {
-        jstring key = (jstring) env->CallObjectMethod(keyIterator,
-                env->GetMethodID(env->FindClass("java/util/Iterator"),
-                "next", "()Ljava/lang/Object;"));
+    jclass Object_class = env->FindClass("java/lang/Object");
+    jmethodID Object_toString = env->GetMethodID(Object_class, "toString", "()Ljava/lang/String;");
 
-        jobject valueObject = env->CallObjectMethod(drmInfoObject,
-                env->GetMethodID(clazz, "get", "(Ljava/lang/String;)Ljava/lang/Object;"), key);
-
-        jstring valString = NULL;
-        if (NULL != valueObject) {
-            valString = (jstring) env->CallObjectMethod(valueObject,
-                env->GetMethodID(env->FindClass("java/lang/Object"),
-                "toString", "()Ljava/lang/String;"));
+    while (env->CallBooleanMethod(keyIterator, Iterator_hasNext)) {
+        ScopedLocalRef<jstring> key(env,
+                (jstring) env->CallObjectMethod(keyIterator, Iterator_next));
+        ScopedLocalRef<jobject> valueObject(env,
+                env->CallObjectMethod(drmInfoObject, DrmInfo_get, key.get()));
+        ScopedLocalRef<jstring> valString(env, NULL);
+        if (NULL != valueObject.get()) {
+            valString.reset((jstring) env->CallObjectMethod(valueObject.get(), Object_toString));
         }
 
-        String8 keyString = Utility::getStringValue(env, key);
-        String8 valueString = Utility::getStringValue(env, valString);
+        String8 keyString = Utility::getStringValue(env, key.get());
+        String8 valueString = Utility::getStringValue(env, valString.get());
         ALOGV("Key: %s | Value: %s", keyString.string(), valueString.string());
 
         drmInfo.put(keyString, valueString);
@@ -508,20 +515,21 @@
     jobject keyIterator
         = env->CallObjectMethod(drmInfoRequest,
                 env->GetMethodID(clazz, "keyIterator", "()Ljava/util/Iterator;"));
+    jmethodID DrmInfoRequest_get = env->GetMethodID(clazz,
+            "get", "(Ljava/lang/String;)Ljava/lang/Object;");
 
-    jmethodID hasNextId = env->GetMethodID(env->FindClass("java/util/Iterator"), "hasNext", "()Z");
+    jclass Iterator_class = env->FindClass("java/util/Iterator");
+    jmethodID Iterator_hasNext = env->GetMethodID(Iterator_class, "hasNext", "()Z");
+    jmethodID Iterator_next = env->GetMethodID(Iterator_class, "next", "()Ljava/lang/Object;");
 
-    while (env->CallBooleanMethod(keyIterator, hasNextId)) {
-        jstring key
-            = (jstring) env->CallObjectMethod(keyIterator,
-                env->GetMethodID(env->FindClass("java/util/Iterator"),
-                                "next", "()Ljava/lang/Object;"));
+    while (env->CallBooleanMethod(keyIterator, Iterator_hasNext)) {
+        ScopedLocalRef<jstring> key(env,
+                (jstring) env->CallObjectMethod(keyIterator, Iterator_next));
+        ScopedLocalRef<jstring> value(env,
+                (jstring) env->CallObjectMethod(drmInfoRequest, DrmInfoRequest_get, key.get()));
 
-        jstring value = (jstring) env->CallObjectMethod(drmInfoRequest,
-                env->GetMethodID(clazz, "get", "(Ljava/lang/String;)Ljava/lang/Object;"), key);
-
-        String8 keyString = Utility::getStringValue(env, key);
-        String8 valueString = Utility::getStringValue(env, value);
+        String8 keyString = Utility::getStringValue(env, key.get());
+        String8 valueString = Utility::getStringValue(env, value.get());
         ALOGV("Key: %s | Value: %s", keyString.string(), valueString.string());
 
         drmInfoReq.put(keyString, valueString);
@@ -552,9 +560,10 @@
             while (it.hasNext()) {
                 String8 key = it.next();
                 String8 value = pDrmInfo->get(key);
-
+                ScopedLocalRef<jstring> keyString(env, env->NewStringUTF(key.string()));
+                ScopedLocalRef<jstring> valueString(env, env->NewStringUTF(value.string()));
                 env->CallVoidMethod(drmInfoObject, putMethodId,
-                    env->NewStringUTF(key.string()), env->NewStringUTF(value.string()));
+                    keyString.get(), valueString.get());
             }
         }
         delete [] pDrmInfo->getData().data;
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 2032f67..af8b0c2 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -561,6 +561,12 @@
         return rsnScriptCCreate(mContext, resName, cacheDir, script, length);
     }
 
+    native int  rsnScriptIntrinsicCreate(int con, int id, int eid);
+    synchronized int nScriptIntrinsicCreate(int id, int eid) {
+        validate();
+        return rsnScriptIntrinsicCreate(mContext, id, eid);
+    }
+
     native int  rsnSamplerCreate(int con, int magFilter, int minFilter,
                                  int wrapS, int wrapT, int wrapR, float aniso);
     synchronized int nSamplerCreate(int magFilter, int minFilter,
diff --git a/graphics/java/android/renderscript/ScriptIntrinsic.java b/graphics/java/android/renderscript/ScriptIntrinsic.java
new file mode 100644
index 0000000..f275fee
--- /dev/null
+++ b/graphics/java/android/renderscript/ScriptIntrinsic.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+
+
+/**
+ * @hide
+ **/
+public class ScriptIntrinsic extends Script {
+    ScriptIntrinsic(int id, RenderScript rs) {
+        super(id, rs);
+    }
+}
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java b/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
new file mode 100644
index 0000000..c7465a7
--- /dev/null
+++ b/graphics/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
@@ -0,0 +1,75 @@
+/*
+ * 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.renderscript;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map.Entry;
+import java.util.HashMap;
+
+
+/**
+ * @hide
+ **/
+public class ScriptIntrinsicConvolve3x3 extends ScriptIntrinsic {
+    private float[] mValues = new float[9];
+    private Allocation mInput;
+
+    ScriptIntrinsicConvolve3x3(int id, RenderScript rs) {
+        super(id, rs);
+    }
+
+    /**
+     * Supported elements types are float, float4, uchar, uchar4
+     *
+     *
+     * @param rs
+     * @param e
+     *
+     * @return ScriptIntrinsicConvolve3x3
+     */
+    public static ScriptIntrinsicConvolve3x3 create(RenderScript rs, Element e) {
+        int id = rs.nScriptIntrinsicCreate(1, e.getID(rs));
+        return new ScriptIntrinsicConvolve3x3(id, rs);
+
+    }
+
+    public void setInput(Allocation ain) {
+        mInput = ain;
+        bindAllocation(ain, 1);
+    }
+
+    public void setColorMatrix(float v[]) {
+        FieldPacker fp = new FieldPacker(9*4);
+        for (int ct=0; ct < mValues.length; ct++) {
+            mValues[ct] = v[ct];
+            fp.addF32(mValues[ct]);
+        }
+        setVar(0, fp);
+    }
+
+    public void forEach(Allocation aout) {
+        forEach(0, null, aout, null);
+    }
+
+}
+
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java b/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java
new file mode 100644
index 0000000..ee5f938
--- /dev/null
+++ b/graphics/java/android/renderscript/ScriptIntrinsicYuvToRGB.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map.Entry;
+import java.util.HashMap;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * @hide
+ **/
+public class ScriptIntrinsicYuvToRGB extends ScriptIntrinsic {
+    ScriptIntrinsicYuvToRGB(int id, RenderScript rs) {
+        super(id, rs);
+    }
+
+
+
+    public static class Builder {
+        RenderScript mRS;
+
+        public Builder(RenderScript rs) {
+            mRS = rs;
+        }
+
+        public void setInputFormat(int inputFormat) {
+
+        }
+
+        public void setOutputFormat(Element e) {
+
+        }
+
+        public ScriptIntrinsicYuvToRGB create() {
+            return null;
+
+        }
+
+    }
+
+}
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 09f6952..a073c1a 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -1071,6 +1071,13 @@
     return ret;
 }
 
+static jint
+nScriptIntrinsicCreate(JNIEnv *_env, jobject _this, RsContext con, jint id, jint eid)
+{
+    LOG_API("nScriptIntrinsicCreate, con(%p) id(%i) element(%p)", con, id, (void *)eid);
+    return (jint)rsScriptIntrinsicCreate(con, id, (RsElement)eid);
+}
+
 // ---------------------------------------------------------------------------
 
 static jint
@@ -1412,6 +1419,7 @@
 {"rsnScriptSetVarObj",               "(IIII)V",                               (void*)nScriptSetVarObj },
 
 {"rsnScriptCCreate",                 "(ILjava/lang/String;Ljava/lang/String;[BI)I",  (void*)nScriptCCreate },
+{"rsnScriptIntrinsicCreate",         "(III)I",                                (void*)nScriptIntrinsicCreate },
 
 {"rsnProgramStoreCreate",            "(IZZZZZZIII)I",                         (void*)nProgramStoreCreate },
 
diff --git a/keystore/java/android/security/AndroidKeyPairGenerator.java b/keystore/java/android/security/AndroidKeyPairGenerator.java
new file mode 100644
index 0000000..c42001b
--- /dev/null
+++ b/keystore/java/android/security/AndroidKeyPairGenerator.java
@@ -0,0 +1,163 @@
+/*
+ * 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.security;
+
+import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
+
+import org.apache.harmony.xnet.provider.jsse.OpenSSLEngine;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyPairGeneratorSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * Provides a way to create instances of a KeyPair which will be placed in the
+ * Android keystore service usable only by the application that called it. This
+ * can be used in conjunction with
+ * {@link java.security.KeyStore#getInstance(String)} using the
+ * {@code "AndroidKeyStore"} type.
+ * <p>
+ * This class can not be directly instantiated and must instead be used via the
+ * {@link KeyPairGenerator#getInstance(String)
+ * KeyPairGenerator.getInstance("AndroidKeyPairGenerator")} API.
+ *
+ * {@hide}
+ */
+@SuppressWarnings("deprecation")
+public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
+    public static final String NAME = "AndroidKeyPairGenerator";
+
+    private android.security.KeyStore mKeyStore;
+
+    private AndroidKeyPairGeneratorSpec 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}
+     * argument before calling this otherwise an {@code IllegalStateException}
+     * will be thrown.
+     * <p>
+     * This will create an entry in the Android keystore service with a
+     * self-signed certificate using the {@code params} specified in the
+     * {@code initialize(params)} call.
+     *
+     * @throws IllegalStateException when called before calling
+     *             {@link KeyPairGenerator#initialize(AlgorithmParameterSpec)}
+     * @see java.security.KeyPairGeneratorSpi#generateKeyPair()
+     */
+    @Override
+    public KeyPair generateKeyPair() {
+        if (mKeyStore == null || mSpec == null) {
+            throw new IllegalStateException(
+                    "Must call initialize with an AndroidKeyPairGeneratorSpec first");
+        }
+
+        final String alias = mSpec.getKeystoreAlias();
+
+        Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+
+        final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
+        mKeyStore.generate(privateKeyAlias);
+
+        final PrivateKey privKey;
+        final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
+        try {
+            privKey = engine.getPrivateKeyById(privateKeyAlias);
+        } catch (InvalidKeyException e) {
+            throw new RuntimeException("Can't get key", e);
+        }
+
+        final byte[] pubKeyBytes = mKeyStore.getPubkey(privateKeyAlias);
+
+        final PublicKey pubKey;
+        try {
+            final KeyFactory keyFact = KeyFactory.getInstance("RSA");
+            pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
+        } catch (NoSuchAlgorithmException e) {
+            throw new IllegalStateException("Can't instantiate RSA key generator", e);
+        } catch (InvalidKeySpecException e) {
+            throw new IllegalStateException("keystore returned invalid key encoding", e);
+        }
+
+        final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+        certGen.setPublicKey(pubKey);
+        certGen.setSerialNumber(mSpec.getSerialNumber());
+        certGen.setSubjectDN(mSpec.getSubjectDN());
+        certGen.setIssuerDN(mSpec.getSubjectDN());
+        certGen.setNotBefore(mSpec.getStartDate());
+        certGen.setNotAfter(mSpec.getEndDate());
+        certGen.setSignatureAlgorithm("sha1WithRSA");
+
+        final X509Certificate cert;
+        try {
+            cert = certGen.generate(privKey);
+        } catch (Exception e) {
+            Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+            throw new IllegalStateException("Can't generate certificate", e);
+        }
+
+        byte[] certBytes;
+        try {
+            certBytes = cert.getEncoded();
+        } catch (CertificateEncodingException e) {
+            Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+            throw new IllegalStateException("Can't get encoding of certificate", e);
+        }
+
+        if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, certBytes)) {
+            Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+            throw new IllegalStateException("Can't store certificate in AndroidKeyStore");
+        }
+
+        return new KeyPair(pubKey, privKey);
+    }
+
+    @Override
+    public void initialize(int keysize, SecureRandom random) {
+        throw new IllegalArgumentException("cannot specify keysize with AndroidKeyPairGenerator");
+    }
+
+    @Override
+    public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+            throws InvalidAlgorithmParameterException {
+        if (params == null) {
+            throw new InvalidAlgorithmParameterException(
+                    "must supply params of type AndroidKeyPairGenericSpec");
+        } else if (!(params instanceof AndroidKeyPairGeneratorSpec)) {
+            throw new InvalidAlgorithmParameterException(
+                    "params must be of type AndroidKeyPairGeneratorSpec");
+        }
+
+        AndroidKeyPairGeneratorSpec spec = (AndroidKeyPairGeneratorSpec) params;
+
+        mSpec = spec;
+        mKeyStore = android.security.KeyStore.getInstance();
+    }
+}
diff --git a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
new file mode 100644
index 0000000..311359c
--- /dev/null
+++ b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
@@ -0,0 +1,144 @@
+/*
+ * 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.security;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * This provides the required parameters needed for initializing the KeyPair
+ * generator that works with
+ * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore
+ * facility</a>.
+ */
+public class AndroidKeyPairGeneratorSpec implements AlgorithmParameterSpec {
+    private final String mKeystoreAlias;
+
+    private final Context mContext;
+
+    private final X500Principal mSubjectDN;
+
+    private final BigInteger mSerialNumber;
+
+    private final Date mStartDate;
+
+    private final Date mEndDate;
+
+    /**
+     * Parameter specification for the "{@code AndroidKeyPairGenerator}"
+     * instance of the {@link java.security.KeyPairGenerator} API. The
+     * {@code context} passed in may be used to pop up some UI to ask the user
+     * to unlock or initialize the Android keystore facility.
+     * <p>
+     * After generation, the {@code keyStoreAlias} is used with the
+     * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)}
+     * interface to retrieve the {@link PrivateKey} and its associated
+     * {@link Certificate} chain.
+     * <p>
+     * The KeyPair generator will create a self-signed certificate with the
+     * properties of {@code subjectDN} as its X.509v3 Subject Distinguished Name
+     * and as its X.509v3 Issuer Distinguished Name, using the specified
+     * {@code serialNumber}, and the validity date starting at {@code startDate}
+     * and ending at {@code endDate}.
+     *
+     * @param context Android context for the activity
+     * @param keyStoreAlias name to use for the generated key in the Android
+     *            keystore
+     * @param subjectDN X.509 v3 Subject Distinguished Name
+     * @param serialNumber X509 v3 certificate serial number
+     * @param startDate the start of the self-signed certificate validity period
+     * @param endDate the end date of the self-signed certificate validity
+     *            period
+     * @throws IllegalArgumentException when any argument is {@code null} or
+     *             {@code endDate} is before {@code startDate}.
+     */
+    public AndroidKeyPairGeneratorSpec(Context context, String keyStoreAlias,
+            X500Principal subjectDN, BigInteger serialNumber, Date startDate, Date endDate) {
+        if (context == null) {
+            throw new IllegalArgumentException("context == null");
+        } else if (TextUtils.isEmpty(keyStoreAlias)) {
+            throw new IllegalArgumentException("keyStoreAlias must not be empty");
+        } else if (subjectDN == null) {
+            throw new IllegalArgumentException("subjectDN == null");
+        } else if (serialNumber == null) {
+            throw new IllegalArgumentException("serialNumber == null");
+        } else if (startDate == null) {
+            throw new IllegalArgumentException("startDate == null");
+        } else if (endDate == null) {
+            throw new IllegalArgumentException("endDate == null");
+        } else if (endDate.before(startDate)) {
+            throw new IllegalArgumentException("endDate < startDate");
+        }
+
+        mContext = context;
+        mKeystoreAlias = keyStoreAlias;
+        mSubjectDN = subjectDN;
+        mSerialNumber = serialNumber;
+        mStartDate = startDate;
+        mEndDate = endDate;
+    }
+
+    /**
+     * @hide
+     */
+    String getKeystoreAlias() {
+        return mKeystoreAlias;
+    }
+
+    /**
+     * @hide
+     */
+    Context getContext() {
+        return mContext;
+    }
+
+    /**
+     * @hide
+     */
+    X500Principal getSubjectDN() {
+        return mSubjectDN;
+    }
+
+    /**
+     * @hide
+     */
+    BigInteger getSerialNumber() {
+        return mSerialNumber;
+    }
+
+    /**
+     * @hide
+     */
+    Date getStartDate() {
+        return mStartDate;
+    }
+
+    /**
+     * @hide
+     */
+    Date getEndDate() {
+        return mEndDate;
+    }
+}
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
new file mode 100644
index 0000000..e19217f
--- /dev/null
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -0,0 +1,447 @@
+/*
+ * 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.security;
+
+import org.apache.harmony.xnet.provider.jsse.OpenSSLEngine;
+
+import android.util.Log;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * A java.security.KeyStore interface for the Android KeyStore. An instance of
+ * it can be created via the {@link java.security.KeyStore#getInstance(String)
+ * KeyStore.getInstance("AndroidKeyStore")} interface. This returns a
+ * java.security.KeyStore backed by this "AndroidKeyStore" implementation.
+ * <p>
+ * This is built on top of Android's keystore daemon. The convention of alias
+ * use is:
+ * <p>
+ * PrivateKeyEntry will have a Credentials.USER_PRIVATE_KEY as the private key,
+ * Credentials.USER_CERTIFICATE as the first certificate in the chain (the one
+ * that corresponds to the private key), and then a Credentials.CA_CERTIFICATE
+ * entry which will have the rest of the chain concatenated in BER format.
+ * <p>
+ * TrustedCertificateEntry will just have a Credentials.CA_CERTIFICATE entry
+ * with a single certificate.
+ *
+ * @hide
+ */
+public class AndroidKeyStore extends KeyStoreSpi {
+    public static final String NAME = "AndroidKeyStore";
+
+    private android.security.KeyStore mKeyStore;
+
+    @Override
+    public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException,
+            UnrecoverableKeyException {
+        if (!isKeyEntry(alias)) {
+            return null;
+        }
+
+        final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
+        try {
+            return engine.getPrivateKeyById(Credentials.USER_PRIVATE_KEY + alias);
+        } catch (InvalidKeyException e) {
+            UnrecoverableKeyException t = new UnrecoverableKeyException("Can't get key");
+            t.initCause(e);
+            throw t;
+        }
+    }
+
+    @Override
+    public Certificate[] engineGetCertificateChain(String alias) {
+        final X509Certificate leaf = (X509Certificate) engineGetCertificate(alias);
+        if (leaf == null) {
+            return null;
+        }
+
+        final Certificate[] caList;
+
+        final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
+        if (caBytes != null) {
+            final Collection<X509Certificate> caChain = toCertificates(caBytes);
+
+            caList = new Certificate[caChain.size() + 1];
+
+            final Iterator<X509Certificate> it = caChain.iterator();
+            int i = 1;
+            while (it.hasNext()) {
+                caList[i++] = it.next();
+            }
+        } else {
+            caList = new Certificate[1];
+        }
+
+        caList[0] = leaf;
+
+        return caList;
+    }
+
+    @Override
+    public Certificate engineGetCertificate(String alias) {
+        byte[] certificate = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
+        if (certificate != null) {
+            return toCertificate(certificate);
+        }
+
+        certificate = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
+        if (certificate != null) {
+            return toCertificate(certificate);
+        }
+
+        return null;
+    }
+
+    private static X509Certificate toCertificate(byte[] bytes) {
+        try {
+            final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+            return (X509Certificate) certFactory
+                    .generateCertificate(new ByteArrayInputStream(bytes));
+        } catch (CertificateException e) {
+            Log.w(NAME, "Couldn't parse certificate in keystore", e);
+            return null;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static Collection<X509Certificate> toCertificates(byte[] bytes) {
+        try {
+            final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+            return (Collection<X509Certificate>) certFactory
+                    .generateCertificates(new ByteArrayInputStream(bytes));
+        } catch (CertificateException e) {
+            Log.w(NAME, "Couldn't parse certificates in keystore", e);
+            return new ArrayList<X509Certificate>();
+        }
+    }
+
+    private Date getModificationDate(String alias) {
+        final long epochMillis = mKeyStore.getmtime(alias);
+        if (epochMillis == -1L) {
+            return null;
+        }
+
+        return new Date(epochMillis);
+    }
+
+    @Override
+    public Date engineGetCreationDate(String alias) {
+        Date d = getModificationDate(Credentials.USER_PRIVATE_KEY + alias);
+        if (d != null) {
+            return d;
+        }
+
+        d = getModificationDate(Credentials.USER_CERTIFICATE + alias);
+        if (d != null) {
+            return d;
+        }
+
+        return getModificationDate(Credentials.CA_CERTIFICATE + alias);
+    }
+
+    @Override
+    public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain)
+            throws KeyStoreException {
+        if ((password != null) && (password.length > 0)) {
+            throw new KeyStoreException("entries cannot be protected with passwords");
+        }
+
+        if (key instanceof PrivateKey) {
+            setPrivateKeyEntry(alias, (PrivateKey) key, chain);
+        } else {
+            throw new KeyStoreException("Only PrivateKeys are supported");
+        }
+    }
+
+    private void setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain)
+            throws KeyStoreException {
+        // Make sure the PrivateKey format is the one we support.
+        final String keyFormat = key.getFormat();
+        if ((keyFormat == null) || (!"PKCS#8".equals(keyFormat))) {
+            throw new KeyStoreException(
+                    "Only PrivateKeys that can be encoded into PKCS#8 are supported");
+        }
+
+        // Make sure we can actually encode the key.
+        final byte[] keyBytes = key.getEncoded();
+        if (keyBytes == null) {
+            throw new KeyStoreException("PrivateKey has no encoding");
+        }
+
+        // Make sure the chain exists since this is a PrivateKey
+        if ((chain == null) || (chain.length == 0)) {
+            throw new KeyStoreException("Must supply at least one Certificate with PrivateKey");
+        }
+
+        // Do chain type checking.
+        X509Certificate[] x509chain = new X509Certificate[chain.length];
+        for (int i = 0; i < chain.length; i++) {
+            if (!"X.509".equals(chain[i].getType())) {
+                throw new KeyStoreException("Certificates must be in X.509 format: invalid cert #"
+                        + i);
+            }
+
+            if (!(chain[i] instanceof X509Certificate)) {
+                throw new KeyStoreException("Certificates must be in X.509 format: invalid cert #"
+                        + i);
+            }
+
+            x509chain[i] = (X509Certificate) chain[i];
+        }
+
+        final byte[] userCertBytes;
+        try {
+            userCertBytes = x509chain[0].getEncoded();
+        } catch (CertificateEncodingException e) {
+            throw new KeyStoreException("Couldn't encode certificate #1", e);
+        }
+
+        /*
+         * If we have a chain, store it in the CA certificate slot for this
+         * alias as concatenated DER-encoded certificates. These can be
+         * deserialized by {@link CertificateFactory#generateCertificates}.
+         */
+        final byte[] chainBytes;
+        if (chain.length > 1) {
+            /*
+             * The chain is passed in as {user_cert, ca_cert_1, ca_cert_2, ...}
+             * so we only need the certificates starting at index 1.
+             */
+            final byte[][] certsBytes = new byte[x509chain.length - 1][];
+            int totalCertLength = 0;
+            for (int i = 0; i < certsBytes.length; i++) {
+                try {
+                    certsBytes[i] = x509chain[i + 1].getEncoded();
+                    totalCertLength += certsBytes[i].length;
+                } catch (CertificateEncodingException e) {
+                    throw new KeyStoreException("Can't encode Certificate #" + i, e);
+                }
+            }
+
+            /*
+             * Serialize this into one byte array so we can later call
+             * CertificateFactory#generateCertificates to recover them.
+             */
+            chainBytes = new byte[totalCertLength];
+            int outputOffset = 0;
+            for (int i = 0; i < certsBytes.length; i++) {
+                final int certLength = certsBytes[i].length;
+                System.arraycopy(certsBytes[i], 0, chainBytes, outputOffset, certLength);
+                outputOffset += certLength;
+                certsBytes[i] = null;
+            }
+        } else {
+            chainBytes = null;
+        }
+
+        /*
+         * Make sure we clear out all the types we know about before trying to
+         * write.
+         */
+        Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+
+        if (!mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, keyBytes)) {
+            throw new KeyStoreException("Couldn't put private key in keystore");
+        } else if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertBytes)) {
+            throw new KeyStoreException("Couldn't put certificate #1 in keystore");
+        } else if (chainBytes != null
+                && !mKeyStore.put(Credentials.CA_CERTIFICATE + alias, chainBytes)) {
+            throw new KeyStoreException("Couldn't put certificate chain in keystore");
+        }
+    }
+
+    @Override
+    public void engineSetKeyEntry(String alias, byte[] userKey, Certificate[] chain)
+            throws KeyStoreException {
+        throw new RuntimeException("Operation not supported because key encoding is unknown");
+    }
+
+    @Override
+    public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
+        if (isKeyEntry(alias)) {
+            throw new KeyStoreException("Entry exists and is not a trusted certificate");
+        }
+
+        final byte[] encoded;
+        try {
+            encoded = cert.getEncoded();
+        } catch (CertificateEncodingException e) {
+            throw new KeyStoreException(e);
+        }
+
+        if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, encoded)) {
+            throw new KeyStoreException("Couldn't insert certificate; is KeyStore initialized?");
+        }
+    }
+
+    @Override
+    public void engineDeleteEntry(String alias) throws KeyStoreException {
+        if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias)) {
+            throw new KeyStoreException("No such entry " + alias);
+        }
+    }
+
+    private Set<String> getUniqueAliases() {
+        final String[] rawAliases = mKeyStore.saw("");
+        if (rawAliases == null) {
+            return new HashSet<String>();
+        }
+
+        final Set<String> aliases = new HashSet<String>(rawAliases.length);
+        for (String alias : rawAliases) {
+            final int idx = alias.indexOf('_');
+            if ((idx == -1) || (alias.length() <= idx)) {
+                Log.e(NAME, "invalid alias: " + alias);
+                continue;
+            }
+
+            aliases.add(new String(alias.substring(idx + 1)));
+        }
+
+        return aliases;
+    }
+
+    @Override
+    public Enumeration<String> engineAliases() {
+        return Collections.enumeration(getUniqueAliases());
+    }
+
+    @Override
+    public boolean engineContainsAlias(String alias) {
+        return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias)
+                || mKeyStore.contains(Credentials.USER_CERTIFICATE + alias)
+                || mKeyStore.contains(Credentials.CA_CERTIFICATE + alias);
+    }
+
+    @Override
+    public int engineSize() {
+        return getUniqueAliases().size();
+    }
+
+    @Override
+    public boolean engineIsKeyEntry(String alias) {
+        return isKeyEntry(alias);
+    }
+
+    private boolean isKeyEntry(String alias) {
+        return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias);
+    }
+
+    @Override
+    public boolean engineIsCertificateEntry(String alias) {
+        return !isKeyEntry(alias) && mKeyStore.contains(Credentials.CA_CERTIFICATE + alias);
+    }
+
+    @Override
+    public String engineGetCertificateAlias(Certificate cert) {
+        if (cert == null) {
+            return null;
+        }
+
+        final Set<String> nonCaEntries = new HashSet<String>();
+
+        /*
+         * First scan the PrivateKeyEntry types. The KeyStoreSpi documentation
+         * says to only compare the first certificate in the chain which is
+         * equivalent to the USER_CERTIFICATE prefix for the Android keystore
+         * convention.
+         */
+        final String[] certAliases = mKeyStore.saw(Credentials.USER_CERTIFICATE);
+        for (String alias : certAliases) {
+            final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
+            if (certBytes == null) {
+                continue;
+            }
+
+            final Certificate c = toCertificate(certBytes);
+            nonCaEntries.add(alias);
+
+            if (cert.equals(c)) {
+                return alias;
+            }
+        }
+
+        /*
+         * Look at all the TrustedCertificateEntry types. Skip all the
+         * PrivateKeyEntry we looked at above.
+         */
+        final String[] caAliases = mKeyStore.saw(Credentials.CA_CERTIFICATE);
+        for (String alias : caAliases) {
+            if (nonCaEntries.contains(alias)) {
+                continue;
+            }
+
+            final byte[] certBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
+            if (certBytes == null) {
+                continue;
+            }
+
+            final Certificate c = toCertificate(mKeyStore.get(Credentials.CA_CERTIFICATE + alias));
+            if (cert.equals(c)) {
+                return alias;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public void engineStore(OutputStream stream, char[] password) throws IOException,
+            NoSuchAlgorithmException, CertificateException {
+        throw new UnsupportedOperationException("Can not serialize AndroidKeyStore to OutputStream");
+    }
+
+    @Override
+    public void engineLoad(InputStream stream, char[] password) throws IOException,
+            NoSuchAlgorithmException, CertificateException {
+        if (stream != null) {
+            throw new IllegalArgumentException("InputStream not supported");
+        }
+
+        if (password != null) {
+            throw new IllegalArgumentException("password not supported");
+        }
+
+        // Unfortunate name collision.
+        mKeyStore = android.security.KeyStore.getInstance();
+    }
+
+}
diff --git a/keystore/java/android/security/AndroidKeyStoreProvider.java b/keystore/java/android/security/AndroidKeyStoreProvider.java
new file mode 100644
index 0000000..40d7e1a
--- /dev/null
+++ b/keystore/java/android/security/AndroidKeyStoreProvider.java
@@ -0,0 +1,39 @@
+/*
+ * 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.security;
+
+import java.security.Provider;
+
+/**
+ * A provider focused on providing JCA interfaces for the Android KeyStore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreProvider extends Provider {
+    public static final String PROVIDER_NAME = "AndroidKeyStoreProvider";
+
+    public AndroidKeyStoreProvider() {
+        super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
+
+        // java.security.KeyStore
+        put("KeyStore." + AndroidKeyStore.NAME, AndroidKeyStore.class.getName());
+
+        // java.security.KeyPairGenerator
+        put("KeyPairGenerator." + AndroidKeyPairGenerator.NAME,
+                AndroidKeyPairGenerator.class.getName());
+    }
+}
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 68ba2b1..72332eb 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -185,4 +185,19 @@
             Log.w(LOGTAG, e.toString());
         }
     }
+
+    /**
+     * Delete all types (private key, certificate, CA certificate) for a
+     * particular {@code alias}. All three can exist for any given alias.
+     * Returns {@code true} if there was at least one of those types.
+     */
+    static boolean deleteAllTypesForAlias(KeyStore keystore, String alias) {
+        /*
+         * Make sure every type is deleted. There can be all three types, so
+         * don't use a conditional here.
+         */
+        return keystore.delKey(Credentials.USER_PRIVATE_KEY + alias)
+                | keystore.delete(Credentials.USER_CERTIFICATE + alias)
+                | keystore.delete(Credentials.CA_CERTIFICATE + alias);
+    }
 }
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index f49c429..4637991 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -26,6 +26,7 @@
 import java.nio.charset.Charsets;
 import java.nio.charset.ModifiedUtf8;
 import java.util.ArrayList;
+import java.util.Date;
 
 /**
  * @hide This should not be made public in its present form because it
@@ -228,6 +229,23 @@
         return ungrant(getKeyBytes(key), getUidBytes(uid));
     }
 
+    private long getmtime(byte[] key) {
+        final ArrayList<byte[]> values = execute('c', key);
+        if (values == null || values.isEmpty()) {
+            return -1L;
+        }
+
+        return Long.parseLong(new String(values.get(0))) * 1000L;
+    }
+
+    /**
+     * Returns the last modification time of the key in milliseconds since the
+     * epoch. Will return -1L if the key could not be found or other error.
+     */
+    public long getmtime(String key) {
+        return getmtime(getKeyBytes(key));
+    }
+
     public int getLastError() {
         return mError;
     }
diff --git a/keystore/java/android/security/package.html b/keystore/java/android/security/package.html
new file mode 100644
index 0000000..610cbf0
--- /dev/null
+++ b/keystore/java/android/security/package.html
@@ -0,0 +1,9 @@
+<HTML>
+<BODY>
+  <p>Provides access to a few facilities of the Android security
+    subsystems.</p>
+  <p>For information on how to use this facility, see the <a
+      href="{@docRoot}guide/topics/security/keystore.html">Android
+      KeyStore facility</a> guide.</p>
+</BODY>
+</HTML>
\ No newline at end of file
diff --git a/keystore/tests/AndroidManifest.xml b/keystore/tests/AndroidManifest.xml
index 1a5f065..415442f 100644
--- a/keystore/tests/AndroidManifest.xml
+++ b/keystore/tests/AndroidManifest.xml
@@ -22,7 +22,7 @@
         <uses-library android:name="android.test.runner" />
     </application>
 
-    <instrumentation android:name=".KeyStoreTestRunner"
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
         android:targetPackage="android.security.tests"
         android:label="KeyStore Tests">
     </instrumentation>
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
new file mode 100644
index 0000000..e6a3750
--- /dev/null
+++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.security;
+
+import android.test.AndroidTestCase;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+public class AndroidKeyPairGeneratorSpecTest extends AndroidTestCase {
+    private static final String TEST_ALIAS_1 = "test1";
+
+    private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
+
+    private static final long NOW_MILLIS = System.currentTimeMillis();
+
+    private static final BigInteger SERIAL_1 = BigInteger.ONE;
+
+    /* We have to round this off because X509v3 doesn't store milliseconds. */
+    private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L));
+
+    @SuppressWarnings("deprecation")
+    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, NOW, NOW_PLUS_10_YEARS);
+
+        assertEquals("Context should be the one specified", getContext(), spec.getContext());
+
+        assertEquals("Alias should be the one specified", TEST_ALIAS_1, spec.getKeystoreAlias());
+
+        assertEquals("subjectDN should be the one specified", TEST_DN_1, spec.getSubjectDN());
+
+        assertEquals("startDate should be the one specified", NOW, spec.getStartDate());
+
+        assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate());
+    }
+
+    public void testConstructor_NullContext_Failure() throws Exception {
+        try {
+            new AndroidKeyPairGeneratorSpec(null, TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,
+                    NOW_PLUS_10_YEARS);
+            fail("Should throw IllegalArgumentException when context is null");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testConstructor_NullKeystoreAlias_Failure() throws Exception {
+        try {
+            new AndroidKeyPairGeneratorSpec(getContext(), null, TEST_DN_1, SERIAL_1, NOW,
+                    NOW_PLUS_10_YEARS);
+            fail("Should throw IllegalArgumentException when keystoreAlias is null");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testConstructor_NullSubjectDN_Failure() throws Exception {
+        try {
+            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, null, SERIAL_1, NOW,
+                    NOW_PLUS_10_YEARS);
+            fail("Should throw IllegalArgumentException when subjectDN is null");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testConstructor_NullSerial_Failure() throws Exception {
+        try {
+            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, null, NOW,
+                    NOW_PLUS_10_YEARS);
+            fail("Should throw IllegalArgumentException when startDate is null");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testConstructor_NullStartDate_Failure() throws Exception {
+        try {
+            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, null,
+                    NOW_PLUS_10_YEARS);
+            fail("Should throw IllegalArgumentException when startDate is null");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testConstructor_NullEndDate_Failure() throws Exception {
+        try {
+            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,
+                    null);
+            fail("Should throw IllegalArgumentException when keystoreAlias is null");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testConstructor_EndBeforeStart_Failure() throws Exception {
+        try {
+            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1,
+                    NOW_PLUS_10_YEARS, NOW);
+            fail("Should throw IllegalArgumentException when end is before start");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+}
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
new file mode 100644
index 0000000..d108caaa
--- /dev/null
+++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.security;
+
+import android.test.AndroidTestCase;
+
+import java.io.ByteArrayInputStream;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+public class AndroidKeyPairGeneratorTest extends AndroidTestCase {
+    private android.security.KeyStore mAndroidKeyStore;
+
+    private java.security.KeyPairGenerator mGenerator;
+
+    private static final String TEST_ALIAS_1 = "test1";
+
+    private static final String TEST_ALIAS_2 = "test2";
+
+    private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
+
+    private static final X500Principal TEST_DN_2 = new X500Principal("CN=test2");
+
+    private static final BigInteger TEST_SERIAL_1 = BigInteger.ONE;
+
+    private static final BigInteger TEST_SERIAL_2 = BigInteger.valueOf(2L);
+
+    private static final long NOW_MILLIS = System.currentTimeMillis();
+
+    /* We have to round this off because X509v3 doesn't store milliseconds. */
+    private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L));
+
+    @SuppressWarnings("deprecation")
+    private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1);
+
+    @Override
+    protected void setUp() throws Exception {
+        mAndroidKeyStore = android.security.KeyStore.getInstance();
+
+        assertTrue(mAndroidKeyStore.reset());
+
+        assertEquals(android.security.KeyStore.State.UNINITIALIZED, mAndroidKeyStore.state());
+
+        assertTrue(mAndroidKeyStore.password("1111"));
+
+        assertEquals(android.security.KeyStore.State.UNLOCKED, mAndroidKeyStore.state());
+
+        assertEquals(0, mAndroidKeyStore.saw("").length);
+
+        mGenerator = java.security.KeyPairGenerator.getInstance(AndroidKeyPairGenerator.NAME);
+    }
+
+    public void testKeyPairGenerator_Initialize_Params_Success() throws Exception {
+        mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
+                TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS));
+    }
+
+    public void testKeyPairGenerator_Initialize_KeySize_Failure() throws Exception {
+        try {
+            mGenerator.initialize(1024);
+            fail("KeyPairGenerator should not support setting the key size");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testKeyPairGenerator_Initialize_KeySizeAndSecureRandom_Failure() throws Exception {
+        try {
+            mGenerator.initialize(1024, new SecureRandom());
+            fail("KeyPairGenerator should not support setting the key size");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testKeyPairGenerator_Initialize_ParamsAndSecureRandom_Failure() throws Exception {
+        mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
+                TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS), new SecureRandom());
+    }
+
+    public void testKeyPairGenerator_GenerateKeyPair_Success() throws Exception {
+        mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
+                TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS));
+
+        final KeyPair pair = mGenerator.generateKeyPair();
+        assertNotNull("The KeyPair returned should not be null", pair);
+
+        assertKeyPairCorrect(pair, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS);
+    }
+
+    public void testKeyPairGenerator_GenerateKeyPair_Replaced_Success() throws Exception {
+        // Generate the first key
+        {
+            mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
+                    TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS));
+            final KeyPair pair1 = mGenerator.generateKeyPair();
+            assertNotNull("The KeyPair returned should not be null", pair1);
+            assertKeyPairCorrect(pair1, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW,
+                    NOW_PLUS_10_YEARS);
+        }
+
+        // Replace the original key
+        {
+            mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_2,
+                    TEST_DN_2, TEST_SERIAL_2, NOW, NOW_PLUS_10_YEARS));
+            final KeyPair pair2 = mGenerator.generateKeyPair();
+            assertNotNull("The KeyPair returned should not be null", pair2);
+            assertKeyPairCorrect(pair2, TEST_ALIAS_2, TEST_DN_2, TEST_SERIAL_2, NOW,
+                    NOW_PLUS_10_YEARS);
+        }
+    }
+
+    private void assertKeyPairCorrect(KeyPair pair, String alias, X500Principal dn,
+            BigInteger serial, Date start, Date end) throws Exception {
+        final PublicKey pubKey = pair.getPublic();
+        assertNotNull("The PublicKey for the KeyPair should be not null", pubKey);
+
+        final PrivateKey privKey = pair.getPrivate();
+        assertNotNull("The PrivateKey for the KeyPair should be not null", privKey);
+
+        final byte[] userCertBytes = mAndroidKeyStore.get(Credentials.USER_CERTIFICATE + alias);
+        assertNotNull("The user certificate should exist for the generated entry", userCertBytes);
+
+        final CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        final Certificate userCert = cf
+                .generateCertificate(new ByteArrayInputStream(userCertBytes));
+
+        assertTrue("Certificate should be in X.509 format", userCert instanceof X509Certificate);
+
+        final X509Certificate x509userCert = (X509Certificate) userCert;
+
+        assertEquals("PublicKey used to sign certificate should match one returned in KeyPair",
+                pubKey, x509userCert.getPublicKey());
+
+        assertEquals("The Subject DN should be the one passed into the params", dn,
+                x509userCert.getSubjectDN());
+
+        assertEquals("The Issuer DN should be the same as the Subject DN", dn,
+                x509userCert.getIssuerDN());
+
+        assertEquals("The Serial should be the one passed into the params", serial,
+                x509userCert.getSerialNumber());
+
+        assertEquals("The notBefore date should be the one passed into the params", start,
+                x509userCert.getNotBefore());
+
+        assertEquals("The notAfter date should be the one passed into the params", end,
+                x509userCert.getNotAfter());
+
+        x509userCert.verify(pubKey);
+
+        final byte[] caCerts = mAndroidKeyStore.get(Credentials.CA_CERTIFICATE + alias);
+        assertNull("A list of CA certificates should not exist for the generated entry", caCerts);
+
+        final byte[] pubKeyBytes = mAndroidKeyStore.getPubkey(Credentials.USER_PRIVATE_KEY + alias);
+        assertNotNull("The keystore should return the public key for the generated key",
+                pubKeyBytes);
+    }
+}
diff --git a/keystore/tests/src/android/security/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
new file mode 100644
index 0000000..bff01b8
--- /dev/null
+++ b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
@@ -0,0 +1,1383 @@
+/*
+ * 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.security;
+
+import android.test.AndroidTestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyStore.Entry;
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.KeyStore.TrustedCertificateEntry;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class AndroidKeyStoreTest extends AndroidTestCase {
+    private android.security.KeyStore mAndroidKeyStore;
+
+    private java.security.KeyStore mKeyStore;
+
+    private static final String TEST_ALIAS_1 = "test1";
+
+    private static final String TEST_ALIAS_2 = "test2";
+
+    private static final String TEST_ALIAS_3 = "test3";
+
+    /*
+     * The keys and certificates below are generated with:
+     *
+     * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem
+     * openssl req -newkey rsa:1024 -keyout userkey.pem -nodes -days 3650 -out userkey.req
+     * mkdir -p demoCA/newcerts
+     * touch demoCA/index.txt
+     * echo "01" > demoCA/serial
+     * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650
+     */
+
+    /**
+     * Generated from above and converted with:
+     *
+     * openssl x509 -outform d -in cacert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
+     */
+    private static final byte[] FAKE_CA_1 = {
+            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0xce, (byte) 0x30, (byte) 0x82,
+            (byte) 0x02, (byte) 0x37, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
+            (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xe1, (byte) 0x6a,
+            (byte) 0xa2, (byte) 0xf4, (byte) 0x2e, (byte) 0x55, (byte) 0x48, (byte) 0x0a,
+            (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
+            (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
+            (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x4f, (byte) 0x31,
+            (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+            (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53,
+            (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03,
+            (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43,
+            (byte) 0x41, (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06,
+            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d,
+            (byte) 0x4d, (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61,
+            (byte) 0x69, (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65,
+            (byte) 0x77, (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06,
+            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12,
+            (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69,
+            (byte) 0x64, (byte) 0x20, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74,
+            (byte) 0x20, (byte) 0x43, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73,
+            (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x31, (byte) 0x32,
+            (byte) 0x30, (byte) 0x38, (byte) 0x31, (byte) 0x34, (byte) 0x31, (byte) 0x36,
+            (byte) 0x35, (byte) 0x35, (byte) 0x34, (byte) 0x34, (byte) 0x5a, (byte) 0x17,
+            (byte) 0x0d, (byte) 0x32, (byte) 0x32, (byte) 0x30, (byte) 0x38, (byte) 0x31,
+            (byte) 0x32, (byte) 0x31, (byte) 0x36, (byte) 0x35, (byte) 0x35, (byte) 0x34,
+            (byte) 0x34, (byte) 0x5a, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b,
+            (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+            (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31,
+            (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+            (byte) 0x04, (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41,
+            (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03,
+            (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d,
+            (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69,
+            (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77,
+            (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03,
+            (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41,
+            (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64,
+            (byte) 0x20, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20,
+            (byte) 0x43, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x30,
+            (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
+            (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
+            (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03,
+            (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89,
+            (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xa3, (byte) 0x72,
+            (byte) 0xab, (byte) 0xd0, (byte) 0xe4, (byte) 0xad, (byte) 0x2f, (byte) 0xe7,
+            (byte) 0xe2, (byte) 0x79, (byte) 0x07, (byte) 0x36, (byte) 0x3d, (byte) 0x0c,
+            (byte) 0x8d, (byte) 0x42, (byte) 0x9a, (byte) 0x0a, (byte) 0x33, (byte) 0x64,
+            (byte) 0xb3, (byte) 0xcd, (byte) 0xb2, (byte) 0xd7, (byte) 0x3a, (byte) 0x42,
+            (byte) 0x06, (byte) 0x77, (byte) 0x45, (byte) 0x29, (byte) 0xe9, (byte) 0xcb,
+            (byte) 0xb7, (byte) 0x4a, (byte) 0xd6, (byte) 0xee, (byte) 0xad, (byte) 0x01,
+            (byte) 0x91, (byte) 0x9b, (byte) 0x0c, (byte) 0x59, (byte) 0xa1, (byte) 0x03,
+            (byte) 0xfa, (byte) 0xf0, (byte) 0x5a, (byte) 0x7c, (byte) 0x4f, (byte) 0xf7,
+            (byte) 0x8d, (byte) 0x36, (byte) 0x0f, (byte) 0x1f, (byte) 0x45, (byte) 0x7d,
+            (byte) 0x1b, (byte) 0x31, (byte) 0xa1, (byte) 0x35, (byte) 0x0b, (byte) 0x00,
+            (byte) 0xed, (byte) 0x7a, (byte) 0xb6, (byte) 0xc8, (byte) 0x4e, (byte) 0xa9,
+            (byte) 0x86, (byte) 0x4c, (byte) 0x7b, (byte) 0x99, (byte) 0x57, (byte) 0x41,
+            (byte) 0x12, (byte) 0xef, (byte) 0x6b, (byte) 0xbc, (byte) 0x3d, (byte) 0x60,
+            (byte) 0xf2, (byte) 0x99, (byte) 0x1a, (byte) 0xcd, (byte) 0xed, (byte) 0x56,
+            (byte) 0xa4, (byte) 0xe5, (byte) 0x36, (byte) 0x9f, (byte) 0x24, (byte) 0x1f,
+            (byte) 0xdc, (byte) 0x89, (byte) 0x40, (byte) 0xc8, (byte) 0x99, (byte) 0x92,
+            (byte) 0xab, (byte) 0x4a, (byte) 0xb5, (byte) 0x61, (byte) 0x45, (byte) 0x62,
+            (byte) 0xff, (byte) 0xa3, (byte) 0x45, (byte) 0x65, (byte) 0xaf, (byte) 0xf6,
+            (byte) 0x27, (byte) 0x30, (byte) 0x51, (byte) 0x0e, (byte) 0x0e, (byte) 0xeb,
+            (byte) 0x79, (byte) 0x0c, (byte) 0xbe, (byte) 0xb3, (byte) 0x0a, (byte) 0x6f,
+            (byte) 0x29, (byte) 0x06, (byte) 0xdc, (byte) 0x2f, (byte) 0x6b, (byte) 0x51,
+            (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3,
+            (byte) 0x81, (byte) 0xb1, (byte) 0x30, (byte) 0x81, (byte) 0xae, (byte) 0x30,
+            (byte) 0x1d, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e,
+            (byte) 0x04, (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0x33, (byte) 0x05,
+            (byte) 0xee, (byte) 0xfe, (byte) 0x6f, (byte) 0x60, (byte) 0xc7, (byte) 0xf9,
+            (byte) 0xa9, (byte) 0xd2, (byte) 0x73, (byte) 0x5c, (byte) 0x8f, (byte) 0x6d,
+            (byte) 0xa2, (byte) 0x2f, (byte) 0x97, (byte) 0x8e, (byte) 0x5d, (byte) 0x51,
+            (byte) 0x30, (byte) 0x7f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d,
+            (byte) 0x23, (byte) 0x04, (byte) 0x78, (byte) 0x30, (byte) 0x76, (byte) 0x80,
+            (byte) 0x14, (byte) 0x33, (byte) 0x05, (byte) 0xee, (byte) 0xfe, (byte) 0x6f,
+            (byte) 0x60, (byte) 0xc7, (byte) 0xf9, (byte) 0xa9, (byte) 0xd2, (byte) 0x73,
+            (byte) 0x5c, (byte) 0x8f, (byte) 0x6d, (byte) 0xa2, (byte) 0x2f, (byte) 0x97,
+            (byte) 0x8e, (byte) 0x5d, (byte) 0x51, (byte) 0xa1, (byte) 0x53, (byte) 0xa4,
+            (byte) 0x51, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
+            (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
+            (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b,
+            (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+            (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31,
+            (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+            (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f,
+            (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e,
+            (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31,
+            (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+            (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41, (byte) 0x6e,
+            (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20,
+            (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x43,
+            (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x82, (byte) 0x09,
+            (byte) 0x00, (byte) 0xe1, (byte) 0x6a, (byte) 0xa2, (byte) 0xf4, (byte) 0x2e,
+            (byte) 0x55, (byte) 0x48, (byte) 0x0a, (byte) 0x30, (byte) 0x0c, (byte) 0x06,
+            (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x05,
+            (byte) 0x30, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30,
+            (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48,
+            (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05,
+            (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x81, (byte) 0x00,
+            (byte) 0x8c, (byte) 0x30, (byte) 0x42, (byte) 0xfa, (byte) 0xeb, (byte) 0x1a,
+            (byte) 0x26, (byte) 0xeb, (byte) 0xda, (byte) 0x56, (byte) 0x32, (byte) 0xf2,
+            (byte) 0x9d, (byte) 0xa5, (byte) 0x24, (byte) 0xd8, (byte) 0x3a, (byte) 0xda,
+            (byte) 0x30, (byte) 0xa6, (byte) 0x8b, (byte) 0x46, (byte) 0xfe, (byte) 0xfe,
+            (byte) 0xdb, (byte) 0xf1, (byte) 0xe6, (byte) 0xe1, (byte) 0x7c, (byte) 0x1b,
+            (byte) 0xe7, (byte) 0x77, (byte) 0x00, (byte) 0xa1, (byte) 0x1c, (byte) 0x19,
+            (byte) 0x17, (byte) 0x73, (byte) 0xb0, (byte) 0xf0, (byte) 0x9d, (byte) 0xf3,
+            (byte) 0x4f, (byte) 0xb6, (byte) 0xbc, (byte) 0xc7, (byte) 0x47, (byte) 0x85,
+            (byte) 0x2a, (byte) 0x4a, (byte) 0xa1, (byte) 0xa5, (byte) 0x58, (byte) 0xf5,
+            (byte) 0xc5, (byte) 0x1a, (byte) 0x51, (byte) 0xb1, (byte) 0x04, (byte) 0x80,
+            (byte) 0xee, (byte) 0x3a, (byte) 0xec, (byte) 0x2f, (byte) 0xe1, (byte) 0xfd,
+            (byte) 0x58, (byte) 0xeb, (byte) 0xed, (byte) 0x82, (byte) 0x9e, (byte) 0x38,
+            (byte) 0xa3, (byte) 0x24, (byte) 0x75, (byte) 0xf7, (byte) 0x3e, (byte) 0xc2,
+            (byte) 0xc5, (byte) 0x27, (byte) 0xeb, (byte) 0x6f, (byte) 0x7b, (byte) 0x50,
+            (byte) 0xda, (byte) 0x43, (byte) 0xdc, (byte) 0x3b, (byte) 0x0b, (byte) 0x6f,
+            (byte) 0x78, (byte) 0x8f, (byte) 0xb0, (byte) 0x66, (byte) 0xe1, (byte) 0x12,
+            (byte) 0x87, (byte) 0x5f, (byte) 0x97, (byte) 0x7b, (byte) 0xca, (byte) 0x14,
+            (byte) 0x79, (byte) 0xf7, (byte) 0xe8, (byte) 0x6c, (byte) 0x72, (byte) 0xdb,
+            (byte) 0x91, (byte) 0x65, (byte) 0x17, (byte) 0x54, (byte) 0xe0, (byte) 0x74,
+            (byte) 0x1d, (byte) 0xac, (byte) 0x47, (byte) 0x04, (byte) 0x12, (byte) 0xe0,
+            (byte) 0xc3, (byte) 0x66, (byte) 0x19, (byte) 0x05, (byte) 0x2e, (byte) 0x7e,
+            (byte) 0xf1, (byte) 0x61
+    };
+
+    /**
+     * Generated from above and converted with:
+     *
+     * openssl pkcs8 -topk8 -outform d -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g'
+     */
+    private static final byte[] FAKE_KEY_1 = new byte[] {
+            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01,
+            (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a,
+            (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01,
+            (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82,
+            (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e,
+            (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81,
+            (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b,
+            (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66,
+            (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a,
+            (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02,
+            (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3,
+            (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d,
+            (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67,
+            (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb,
+            (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2,
+            (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79,
+            (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce,
+            (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08,
+            (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b,
+            (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4,
+            (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d,
+            (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23,
+            (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08,
+            (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1,
+            (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4,
+            (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16,
+            (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e,
+            (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01,
+            (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16,
+            (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98,
+            (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf,
+            (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a,
+            (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2,
+            (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc,
+            (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5,
+            (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a,
+            (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b,
+            (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9,
+            (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12,
+            (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e,
+            (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d,
+            (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2,
+            (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d,
+            (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc,
+            (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98,
+            (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96,
+            (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30,
+            (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e,
+            (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad,
+            (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f,
+            (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89,
+            (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13,
+            (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a,
+            (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e,
+            (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa,
+            (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47,
+            (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44,
+            (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22,
+            (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10,
+            (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45,
+            (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4,
+            (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda,
+            (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1,
+            (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab,
+            (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7,
+            (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc,
+            (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d,
+            (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82,
+            (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3,
+            (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a,
+            (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9,
+            (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6,
+            (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00,
+            (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd,
+            (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb,
+            (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4,
+            (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0,
+            (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2,
+            (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce,
+            (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a,
+            (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21,
+            (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d,
+            (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1,
+            (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41,
+            (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce,
+            (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0,
+            (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40,
+            (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a,
+            (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c,
+            (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90,
+            (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf,
+            (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb,
+            (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14,
+            (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab,
+            (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02,
+            (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67,
+            (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d,
+            (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d,
+            (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b,
+            (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2,
+            (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28,
+            (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd,
+            (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d,
+            (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b,
+            (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1,
+            (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51
+    };
+
+    /**
+     * Generated from above and converted with:
+     *
+     * openssl x509 -outform d -in usercert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
+     */
+    private static final byte[] FAKE_USER_1 = new byte[] {
+            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x95, (byte) 0x30, (byte) 0x82,
+            (byte) 0x01, (byte) 0xfe, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
+            (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0d,
+            (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
+            (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05,
+            (byte) 0x00, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
+            (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
+            (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b,
+            (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+            (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31,
+            (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+            (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f,
+            (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e,
+            (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31,
+            (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+            (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41, (byte) 0x6e,
+            (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20,
+            (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x43,
+            (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x30, (byte) 0x1e,
+            (byte) 0x17, (byte) 0x0d, (byte) 0x31, (byte) 0x32, (byte) 0x30, (byte) 0x38,
+            (byte) 0x31, (byte) 0x34, (byte) 0x32, (byte) 0x33, (byte) 0x32, (byte) 0x35,
+            (byte) 0x34, (byte) 0x38, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, (byte) 0x32,
+            (byte) 0x32, (byte) 0x30, (byte) 0x38, (byte) 0x31, (byte) 0x32, (byte) 0x32,
+            (byte) 0x33, (byte) 0x32, (byte) 0x35, (byte) 0x34, (byte) 0x38, (byte) 0x5a,
+            (byte) 0x30, (byte) 0x55, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09,
+            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13,
+            (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
+            (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08,
+            (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31, (byte) 0x1b,
+            (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
+            (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41, (byte) 0x6e, (byte) 0x64,
+            (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20, (byte) 0x54,
+            (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x43, (byte) 0x61,
+            (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x31, (byte) 0x1c, (byte) 0x30,
+            (byte) 0x1a, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03,
+            (byte) 0x13, (byte) 0x13, (byte) 0x73, (byte) 0x65, (byte) 0x72, (byte) 0x76,
+            (byte) 0x65, (byte) 0x72, (byte) 0x31, (byte) 0x2e, (byte) 0x65, (byte) 0x78,
+            (byte) 0x61, (byte) 0x6d, (byte) 0x70, (byte) 0x6c, (byte) 0x65, (byte) 0x2e,
+            (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, (byte) 0x81, (byte) 0x9f,
+            (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
+            (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
+            (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x8d,
+            (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89, (byte) 0x02, (byte) 0x81,
+            (byte) 0x81, (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6,
+            (byte) 0x5b, (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c,
+            (byte) 0x66, (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86,
+            (byte) 0x8a, (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3,
+            (byte) 0x02, (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08,
+            (byte) 0xf3, (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04,
+            (byte) 0x6d, (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f,
+            (byte) 0x67, (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c,
+            (byte) 0xcb, (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30,
+            (byte) 0xe2, (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5,
+            (byte) 0x79, (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b,
+            (byte) 0xce, (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb,
+            (byte) 0x08, (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff,
+            (byte) 0x3b, (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9,
+            (byte) 0xc4, (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29,
+            (byte) 0x0d, (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b,
+            (byte) 0x23, (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78,
+            (byte) 0x08, (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5,
+            (byte) 0xf1, (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19,
+            (byte) 0xb4, (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03,
+            (byte) 0x16, (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce,
+            (byte) 0x9e, (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03,
+            (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3, (byte) 0x7b, (byte) 0x30,
+            (byte) 0x79, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
+            (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00,
+            (byte) 0x30, (byte) 0x2c, (byte) 0x06, (byte) 0x09, (byte) 0x60, (byte) 0x86,
+            (byte) 0x48, (byte) 0x01, (byte) 0x86, (byte) 0xf8, (byte) 0x42, (byte) 0x01,
+            (byte) 0x0d, (byte) 0x04, (byte) 0x1f, (byte) 0x16, (byte) 0x1d, (byte) 0x4f,
+            (byte) 0x70, (byte) 0x65, (byte) 0x6e, (byte) 0x53, (byte) 0x53, (byte) 0x4c,
+            (byte) 0x20, (byte) 0x47, (byte) 0x65, (byte) 0x6e, (byte) 0x65, (byte) 0x72,
+            (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x64, (byte) 0x20, (byte) 0x43,
+            (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69,
+            (byte) 0x63, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x1d,
+            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04,
+            (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0x32, (byte) 0xa1, (byte) 0x1e,
+            (byte) 0x6b, (byte) 0x69, (byte) 0x04, (byte) 0xfe, (byte) 0xb3, (byte) 0xcd,
+            (byte) 0xf8, (byte) 0xbb, (byte) 0x14, (byte) 0xcd, (byte) 0xff, (byte) 0xd4,
+            (byte) 0x16, (byte) 0xc3, (byte) 0xab, (byte) 0x44, (byte) 0x2f, (byte) 0x30,
+            (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23,
+            (byte) 0x04, (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14,
+            (byte) 0x33, (byte) 0x05, (byte) 0xee, (byte) 0xfe, (byte) 0x6f, (byte) 0x60,
+            (byte) 0xc7, (byte) 0xf9, (byte) 0xa9, (byte) 0xd2, (byte) 0x73, (byte) 0x5c,
+            (byte) 0x8f, (byte) 0x6d, (byte) 0xa2, (byte) 0x2f, (byte) 0x97, (byte) 0x8e,
+            (byte) 0x5d, (byte) 0x51, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
+            (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
+            (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03,
+            (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x46, (byte) 0x42, (byte) 0xef,
+            (byte) 0x56, (byte) 0x89, (byte) 0x78, (byte) 0x90, (byte) 0x38, (byte) 0x24,
+            (byte) 0x9f, (byte) 0x8c, (byte) 0x7a, (byte) 0xce, (byte) 0x7a, (byte) 0xa5,
+            (byte) 0xb5, (byte) 0x1e, (byte) 0x74, (byte) 0x96, (byte) 0x34, (byte) 0x49,
+            (byte) 0x8b, (byte) 0xed, (byte) 0x44, (byte) 0xb3, (byte) 0xc9, (byte) 0x05,
+            (byte) 0xd7, (byte) 0x48, (byte) 0x55, (byte) 0x52, (byte) 0x59, (byte) 0x15,
+            (byte) 0x0b, (byte) 0xaa, (byte) 0x16, (byte) 0x86, (byte) 0xd2, (byte) 0x8e,
+            (byte) 0x16, (byte) 0x99, (byte) 0xe8, (byte) 0x5f, (byte) 0x11, (byte) 0x71,
+            (byte) 0x42, (byte) 0x55, (byte) 0xd1, (byte) 0xc4, (byte) 0x6f, (byte) 0x2e,
+            (byte) 0xa9, (byte) 0x64, (byte) 0x6f, (byte) 0xd8, (byte) 0xfd, (byte) 0x43,
+            (byte) 0x13, (byte) 0x24, (byte) 0xaa, (byte) 0x67, (byte) 0xe6, (byte) 0xf5,
+            (byte) 0xca, (byte) 0x80, (byte) 0x5e, (byte) 0x3a, (byte) 0x3e, (byte) 0xcc,
+            (byte) 0x4f, (byte) 0xba, (byte) 0x87, (byte) 0xe6, (byte) 0xae, (byte) 0xbf,
+            (byte) 0x8f, (byte) 0xd5, (byte) 0x28, (byte) 0x38, (byte) 0x58, (byte) 0x30,
+            (byte) 0x24, (byte) 0xf6, (byte) 0x53, (byte) 0x5b, (byte) 0x41, (byte) 0x53,
+            (byte) 0xe6, (byte) 0x45, (byte) 0xbc, (byte) 0xbe, (byte) 0xe6, (byte) 0xbb,
+            (byte) 0x5d, (byte) 0xd8, (byte) 0xa7, (byte) 0xf9, (byte) 0x64, (byte) 0x99,
+            (byte) 0x04, (byte) 0x43, (byte) 0x75, (byte) 0xd7, (byte) 0x2d, (byte) 0x32,
+            (byte) 0x0a, (byte) 0x94, (byte) 0xaf, (byte) 0x06, (byte) 0x34, (byte) 0xae,
+            (byte) 0x46, (byte) 0xbd, (byte) 0xda, (byte) 0x00, (byte) 0x0e, (byte) 0x25,
+            (byte) 0xc2, (byte) 0xf7, (byte) 0xc9, (byte) 0xc3, (byte) 0x65, (byte) 0xd2,
+            (byte) 0x08, (byte) 0x41, (byte) 0x0a, (byte) 0xf3, (byte) 0x72
+    };
+
+    /**
+     * The amount of time to allow before and after expected time for variance
+     * in timing tests.
+     */
+    private static final long SLOP_TIME_MILLIS = 15000L;
+
+    @Override
+    protected void setUp() throws Exception {
+        mAndroidKeyStore = android.security.KeyStore.getInstance();
+
+        assertTrue(mAndroidKeyStore.reset());
+
+        assertEquals(android.security.KeyStore.State.UNINITIALIZED, mAndroidKeyStore.state());
+
+        assertTrue(mAndroidKeyStore.password("1111"));
+
+        assertEquals(android.security.KeyStore.State.UNLOCKED, mAndroidKeyStore.state());
+
+        assertEquals(0, mAndroidKeyStore.saw("").length);
+
+        mKeyStore = java.security.KeyStore.getInstance(AndroidKeyStore.NAME);
+    }
+
+    private void assertAliases(final String[] expectedAliases) throws KeyStoreException {
+        final Enumeration<String> aliases = mKeyStore.aliases();
+        int count = 0;
+
+        final Set<String> expectedSet = new HashSet<String>();
+        expectedSet.addAll(Arrays.asList(expectedAliases));
+
+        while (aliases.hasMoreElements()) {
+            count++;
+            final String alias = aliases.nextElement();
+            assertTrue("The alias should be in the expected set", expectedSet.contains(alias));
+            expectedSet.remove(alias);
+        }
+        assertTrue("The expected set and actual set should be exactly equal", expectedSet.isEmpty());
+        assertEquals("There should be the correct number of keystore entries",
+                expectedAliases.length, count);
+    }
+
+    public void testKeyStore_Aliases_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertAliases(new String[] {});
+
+        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1));
+
+        assertAliases(new String[] { TEST_ALIAS_1 });
+
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
+
+        assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2 });
+    }
+
+    public void testKeyStore_Aliases_NotInitialized_Failure() throws Exception {
+        try {
+            mKeyStore.aliases();
+            fail("KeyStore should throw exception when not initialized");
+        } catch (KeyStoreException success) {
+        }
+    }
+
+    public void testKeyStore_ContainsAliases_PrivateAndCA_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertAliases(new String[] {});
+
+        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1));
+
+        assertTrue("Should contain generated private key", mKeyStore.containsAlias(TEST_ALIAS_1));
+
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
+
+        assertTrue("Should contain added CA certificate", mKeyStore.containsAlias(TEST_ALIAS_2));
+
+        assertFalse("Should not contain unadded certificate alias",
+                mKeyStore.containsAlias(TEST_ALIAS_3));
+    }
+
+    public void testKeyStore_ContainsAliases_CAOnly_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
+
+        assertTrue("Should contain added CA certificate", mKeyStore.containsAlias(TEST_ALIAS_2));
+    }
+
+    public void testKeyStore_ContainsAliases_NonExistent_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertFalse("Should contain added CA certificate", mKeyStore.containsAlias(TEST_ALIAS_1));
+    }
+
+    public void testKeyStore_DeleteEntry_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        // TEST_ALIAS_1
+        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
+                FAKE_KEY_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        // TEST_ALIAS_2
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
+
+        // TEST_ALIAS_3
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_3, FAKE_CA_1));
+
+        assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2, TEST_ALIAS_3 });
+
+        mKeyStore.deleteEntry(TEST_ALIAS_1);
+
+        assertAliases(new String[] { TEST_ALIAS_2, TEST_ALIAS_3 });
+
+        mKeyStore.deleteEntry(TEST_ALIAS_3);
+
+        assertAliases(new String[] { TEST_ALIAS_2 });
+
+        mKeyStore.deleteEntry(TEST_ALIAS_2);
+
+        assertAliases(new String[] { });
+    }
+
+    public void testKeyStore_DeleteEntry_EmptyStore_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        try {
+            mKeyStore.deleteEntry(TEST_ALIAS_1);
+            fail("Should throw KeyStoreException with non-existent alias");
+        } catch (KeyStoreException success) {
+        }
+    }
+
+    public void testKeyStore_DeleteEntry_NonExistent_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        // TEST_ALIAS_1
+        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
+                FAKE_KEY_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        try {
+            mKeyStore.deleteEntry(TEST_ALIAS_2);
+            fail("Should throw KeyStoreException with non-existent alias");
+        } catch (KeyStoreException success) {
+        }
+    }
+
+    public void testKeyStore_GetCertificate_Single_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        assertAliases(new String[] { TEST_ALIAS_1 });
+
+        assertNull("Certificate should not exist in keystore",
+                mKeyStore.getCertificate(TEST_ALIAS_2));
+
+        Certificate retrieved = mKeyStore.getCertificate(TEST_ALIAS_1);
+
+        assertNotNull("Retrieved certificate should not be null", retrieved);
+
+        CertificateFactory f = CertificateFactory.getInstance("X.509");
+        Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+        assertEquals("Actual and retrieved certificates should be the same", actual, retrieved);
+    }
+
+    public void testKeyStore_GetCertificate_NonExist_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertNull("Certificate should not exist in keystore",
+                mKeyStore.getCertificate(TEST_ALIAS_1));
+    }
+
+    public void testKeyStore_GetCertificateAlias_CAEntry_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        CertificateFactory f = CertificateFactory.getInstance("X.509");
+        Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+        assertEquals("Stored certificate alias should be found", TEST_ALIAS_1,
+                mKeyStore.getCertificateAlias(actual));
+    }
+
+    public void testKeyStore_GetCertificateAlias_PrivateKeyEntry_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
+                FAKE_KEY_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        CertificateFactory f = CertificateFactory.getInstance("X.509");
+        Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+
+        assertEquals("Stored certificate alias should be found", TEST_ALIAS_1,
+                mKeyStore.getCertificateAlias(actual));
+    }
+
+    public void testKeyStore_GetCertificateAlias_CAEntry_WithPrivateKeyUsingCA_Success()
+            throws Exception {
+        mKeyStore.load(null, null);
+
+        // Insert TrustedCertificateEntry with CA name
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
+
+        // Insert PrivateKeyEntry that uses the same CA
+        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
+                FAKE_KEY_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        CertificateFactory f = CertificateFactory.getInstance("X.509");
+        Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+        assertEquals("Stored certificate alias should be found", TEST_ALIAS_2,
+                mKeyStore.getCertificateAlias(actual));
+    }
+
+    public void testKeyStore_GetCertificateAlias_NonExist_Empty_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        CertificateFactory f = CertificateFactory.getInstance("X.509");
+        Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+        assertNull("Stored certificate alias should not be found",
+                mKeyStore.getCertificateAlias(actual));
+    }
+
+    public void testKeyStore_GetCertificateAlias_NonExist_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        CertificateFactory f = CertificateFactory.getInstance("X.509");
+        Certificate userCert = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+
+        assertNull("Stored certificate alias should be found",
+                mKeyStore.getCertificateAlias(userCert));
+    }
+
+    public void testKeyStore_GetCertificateChain_SingleLength_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
+                FAKE_KEY_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        Certificate[] expected = new Certificate[2];
+        expected[0] = cf.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+        expected[1] = cf.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+        Certificate[] actual = mKeyStore.getCertificateChain(TEST_ALIAS_1);
+
+        assertNotNull("Returned certificate chain should not be null", actual);
+        assertEquals("Returned certificate chain should be correct size", expected.length,
+                actual.length);
+        assertEquals("First certificate should be user certificate", expected[0], actual[0]);
+        assertEquals("Second certificate should be CA certificate", expected[1], actual[1]);
+
+        // Negative test when keystore is populated.
+        assertNull("Stored certificate alias should not be found",
+                mKeyStore.getCertificateChain(TEST_ALIAS_2));
+    }
+
+    public void testKeyStore_GetCertificateChain_NonExist_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertNull("Stored certificate alias should not be found",
+                mKeyStore.getCertificateChain(TEST_ALIAS_1));
+    }
+
+    public void testKeyStore_GetCreationDate_PrivateKeyEntry_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
+                FAKE_KEY_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        Date now = new Date();
+        Date actual = mKeyStore.getCreationDate(TEST_ALIAS_1);
+
+        Date expectedAfter = new Date(now.getTime() - SLOP_TIME_MILLIS);
+        Date expectedBefore = new Date(now.getTime() + SLOP_TIME_MILLIS);
+
+        assertTrue("Time should be close to current time", actual.before(expectedBefore));
+        assertTrue("Time should be close to current time", actual.after(expectedAfter));
+    }
+
+    public void testKeyStore_GetCreationDate_CAEntry_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        Date now = new Date();
+        Date actual = mKeyStore.getCreationDate(TEST_ALIAS_1);
+        assertNotNull("Certificate should be found", actual);
+
+        Date expectedAfter = new Date(now.getTime() - SLOP_TIME_MILLIS);
+        Date expectedBefore = new Date(now.getTime() + SLOP_TIME_MILLIS);
+
+        assertTrue("Time should be close to current time", actual.before(expectedBefore));
+        assertTrue("Time should be close to current time", actual.after(expectedAfter));
+    }
+
+    public void testKeyStore_GetEntry_NullParams_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
+                FAKE_KEY_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+        assertNotNull("Entry should exist", entry);
+
+        assertTrue("Should be a PrivateKeyEntry", entry instanceof PrivateKeyEntry);
+
+        PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry;
+
+        assertPrivateKeyEntryEquals(keyEntry, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
+    }
+
+    private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, byte[] key, byte[] cert,
+            byte[] ca) throws Exception {
+        KeyFactory keyFact = KeyFactory.getInstance("RSA");
+        PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(key));
+
+        assertEquals("Returned PrivateKey should be what we inserted", expectedKey,
+                keyEntry.getPrivateKey());
+
+        CertificateFactory certFact = CertificateFactory.getInstance("X.509");
+        Certificate expectedCert = certFact.generateCertificate(new ByteArrayInputStream(cert));
+
+        assertEquals("Returned Certificate should be what we inserted", expectedCert,
+                keyEntry.getCertificate());
+
+        Certificate[] actualChain = keyEntry.getCertificateChain();
+
+        assertEquals("First certificate in chain should be user cert", expectedCert, actualChain[0]);
+
+        if (ca == null) {
+            assertEquals("Certificate chain should not include CAs", 1, actualChain.length);
+        } else {
+            @SuppressWarnings("unchecked")
+            Collection<Certificate> expectedChain = (Collection<Certificate>) certFact
+                    .generateCertificates(new ByteArrayInputStream(ca));
+
+            int i = 1;
+            final Iterator<Certificate> it = expectedChain.iterator();
+            while (it.hasNext()) {
+                assertEquals("CA chain certificate should equal what we put in", it.next(),
+                        actualChain[i++]);
+            }
+        }
+    }
+
+    public void testKeyStore_GetEntry_Nonexistent_NullParams_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertNull("A non-existent entry should return null",
+                mKeyStore.getEntry(TEST_ALIAS_1, null));
+    }
+
+    public void testKeyStore_GetKey_NoPassword_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
+                FAKE_KEY_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
+        assertNotNull("Key should exist", key);
+
+        assertTrue("Should be a RSAPrivateKey", key instanceof RSAPrivateKey);
+
+        RSAPrivateKey actualKey = (RSAPrivateKey) key;
+
+        KeyFactory keyFact = KeyFactory.getInstance("RSA");
+        PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
+
+        assertEquals("Inserted key should be same as retrieved key", actualKey, expectedKey);
+    }
+
+    public void testKeyStore_GetKey_Certificate_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        assertNull("Certificate entries should return null", mKeyStore.getKey(TEST_ALIAS_1, null));
+    }
+
+    public void testKeyStore_GetKey_NonExistent_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertNull("A non-existent entry should return null", mKeyStore.getKey(TEST_ALIAS_1, null));
+    }
+
+    public void testKeyStore_GetProvider_Success() throws Exception {
+        assertEquals(AndroidKeyStoreProvider.PROVIDER_NAME, mKeyStore.getProvider().getName());
+    }
+
+    public void testKeyStore_GetType_Success() throws Exception {
+        assertEquals(AndroidKeyStore.NAME, mKeyStore.getType());
+    }
+
+    public void testKeyStore_IsCertificateEntry_CA_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        assertTrue("Should return true for CA certificate",
+                mKeyStore.isCertificateEntry(TEST_ALIAS_1));
+    }
+
+    public void testKeyStore_IsCertificateEntry_PrivateKey_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
+                FAKE_KEY_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        assertFalse("Should return false for PrivateKeyEntry",
+                mKeyStore.isCertificateEntry(TEST_ALIAS_1));
+    }
+
+    public void testKeyStore_IsCertificateEntry_NonExist_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertFalse("Should return false for non-existent entry",
+                mKeyStore.isCertificateEntry(TEST_ALIAS_1));
+    }
+
+    public void testKeyStore_IsKeyEntry_PrivateKey_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
+                FAKE_KEY_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        assertTrue("Should return true for PrivateKeyEntry", mKeyStore.isKeyEntry(TEST_ALIAS_1));
+    }
+
+    public void testKeyStore_IsKeyEntry_CA_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        assertFalse("Should return false for CA certificate", mKeyStore.isKeyEntry(TEST_ALIAS_1));
+    }
+
+    public void testKeyStore_IsKeyEntry_NonExist_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertFalse("Should return false for non-existent entry",
+                mKeyStore.isKeyEntry(TEST_ALIAS_1));
+    }
+
+    public void testKeyStore_SetCertificate_CA_Success() throws Exception {
+        final CertificateFactory f = CertificateFactory.getInstance("X.509");
+        final Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+        mKeyStore.load(null, null);
+
+        mKeyStore.setCertificateEntry(TEST_ALIAS_1, actual);
+        assertAliases(new String[] { TEST_ALIAS_1 });
+
+        Certificate retrieved = mKeyStore.getCertificate(TEST_ALIAS_1);
+
+        assertEquals("Retrieved certificate should be the same as the one inserted", actual,
+                retrieved);
+    }
+
+    public void testKeyStore_SetCertificate_CAExists_Overwrite_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        assertAliases(new String[] { TEST_ALIAS_1 });
+
+        final CertificateFactory f = CertificateFactory.getInstance("X.509");
+        final Certificate cert = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+        // TODO have separate FAKE_CA for second test
+        mKeyStore.setCertificateEntry(TEST_ALIAS_1, cert);
+
+        assertAliases(new String[] { TEST_ALIAS_1 });
+    }
+
+    public void testKeyStore_SetCertificate_PrivateKeyExists_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
+                FAKE_KEY_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_USER_1));
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        assertAliases(new String[] { TEST_ALIAS_1 });
+
+        final CertificateFactory f = CertificateFactory.getInstance("X.509");
+        final Certificate cert = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+        try {
+            mKeyStore.setCertificateEntry(TEST_ALIAS_1, cert);
+            fail("Should throw when trying to overwrite a PrivateKey entry with a Certificate");
+        } catch (KeyStoreException success) {
+        }
+    }
+
+    public void testKeyStore_SetEntry_PrivateKeyEntry_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        KeyFactory keyFact = KeyFactory.getInstance("RSA");
+        PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
+
+        final CertificateFactory f = CertificateFactory.getInstance("X.509");
+
+        final Certificate[] expectedChain = new Certificate[2];
+        expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+        expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+        PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain);
+
+        mKeyStore.setEntry(TEST_ALIAS_1, expected, null);
+
+        Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+        assertNotNull("Retrieved entry should exist", actualEntry);
+
+        assertTrue("Retrieved entry should be of type PrivateKeyEntry",
+                actualEntry instanceof PrivateKeyEntry);
+
+        PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
+
+        assertPrivateKeyEntryEquals(actual, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
+    }
+
+    public void testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_PrivateKeyEntry_Success()
+            throws Exception {
+        mKeyStore.load(null, null);
+
+        final KeyFactory keyFact = KeyFactory.getInstance("RSA");
+        final CertificateFactory f = CertificateFactory.getInstance("X.509");
+
+        // Start with PrivateKeyEntry
+        {
+            PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
+
+            final Certificate[] expectedChain = new Certificate[2];
+            expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+            expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+            PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain);
+
+            mKeyStore.setEntry(TEST_ALIAS_1, expected, null);
+
+            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+            assertNotNull("Retrieved entry should exist", actualEntry);
+
+            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
+                    actualEntry instanceof PrivateKeyEntry);
+
+            PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
+
+            assertPrivateKeyEntryEquals(actual, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
+        }
+
+        // TODO make entirely new test vector for the overwrite
+        // Replace with PrivateKeyEntry
+        {
+            PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
+
+            final Certificate[] expectedChain = new Certificate[2];
+            expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+            expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+            PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain);
+
+            mKeyStore.setEntry(TEST_ALIAS_1, expected, null);
+
+            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+            assertNotNull("Retrieved entry should exist", actualEntry);
+
+            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
+                    actualEntry instanceof PrivateKeyEntry);
+
+            PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
+
+            assertPrivateKeyEntryEquals(actual, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
+        }
+    }
+
+    public void testKeyStore_SetEntry_CAEntry_Overwrites_PrivateKeyEntry_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        final CertificateFactory f = CertificateFactory.getInstance("X.509");
+
+        // Start with TrustedCertificateEntry
+        {
+            final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+            TrustedCertificateEntry expectedCertEntry = new TrustedCertificateEntry(caCert);
+            mKeyStore.setEntry(TEST_ALIAS_1, expectedCertEntry, null);
+
+            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+            assertNotNull("Retrieved entry should exist", actualEntry);
+            assertTrue("Retrieved entry should be of type TrustedCertificateEntry",
+                    actualEntry instanceof TrustedCertificateEntry);
+            TrustedCertificateEntry actualCertEntry = (TrustedCertificateEntry) actualEntry;
+            assertEquals("Stored and retrieved certificates should be the same",
+                    expectedCertEntry.getTrustedCertificate(),
+                    actualCertEntry.getTrustedCertificate());
+        }
+
+        // Replace with PrivateKeyEntry
+        {
+            KeyFactory keyFact = KeyFactory.getInstance("RSA");
+            PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
+            final Certificate[] expectedChain = new Certificate[2];
+            expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+            expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+            PrivateKeyEntry expectedPrivEntry = new PrivateKeyEntry(expectedKey, expectedChain);
+
+            mKeyStore.setEntry(TEST_ALIAS_1, expectedPrivEntry, null);
+
+            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+            assertNotNull("Retrieved entry should exist", actualEntry);
+            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
+                    actualEntry instanceof PrivateKeyEntry);
+
+            PrivateKeyEntry actualPrivEntry = (PrivateKeyEntry) actualEntry;
+            assertPrivateKeyEntryEquals(actualPrivEntry, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
+        }
+    }
+
+    public void testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_CAEntry_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        final CertificateFactory f = CertificateFactory.getInstance("X.509");
+
+        final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+        // Start with PrivateKeyEntry
+        {
+            KeyFactory keyFact = KeyFactory.getInstance("RSA");
+            PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
+            final Certificate[] expectedChain = new Certificate[2];
+            expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+            expectedChain[1] = caCert;
+
+            PrivateKeyEntry expectedPrivEntry = new PrivateKeyEntry(expectedKey, expectedChain);
+
+            mKeyStore.setEntry(TEST_ALIAS_1, expectedPrivEntry, null);
+
+            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+            assertNotNull("Retrieved entry should exist", actualEntry);
+            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
+                    actualEntry instanceof PrivateKeyEntry);
+
+            PrivateKeyEntry actualPrivEntry = (PrivateKeyEntry) actualEntry;
+            assertPrivateKeyEntryEquals(actualPrivEntry, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
+        }
+
+        // Replace with TrustedCertificateEntry
+        {
+            TrustedCertificateEntry expectedCertEntry = new TrustedCertificateEntry(caCert);
+            mKeyStore.setEntry(TEST_ALIAS_1, expectedCertEntry, null);
+
+            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+            assertNotNull("Retrieved entry should exist", actualEntry);
+            assertTrue("Retrieved entry should be of type TrustedCertificateEntry",
+                    actualEntry instanceof TrustedCertificateEntry);
+            TrustedCertificateEntry actualCertEntry = (TrustedCertificateEntry) actualEntry;
+            assertEquals("Stored and retrieved certificates should be the same",
+                    expectedCertEntry.getTrustedCertificate(),
+                    actualCertEntry.getTrustedCertificate());
+        }
+    }
+
+    public void testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_ShortPrivateKeyEntry_Success()
+            throws Exception {
+        mKeyStore.load(null, null);
+
+        final CertificateFactory f = CertificateFactory.getInstance("X.509");
+
+        final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+        // Start with PrivateKeyEntry
+        {
+            KeyFactory keyFact = KeyFactory.getInstance("RSA");
+            PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
+            final Certificate[] expectedChain = new Certificate[2];
+            expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+            expectedChain[1] = caCert;
+
+            PrivateKeyEntry expectedPrivEntry = new PrivateKeyEntry(expectedKey, expectedChain);
+
+            mKeyStore.setEntry(TEST_ALIAS_1, expectedPrivEntry, null);
+
+            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+            assertNotNull("Retrieved entry should exist", actualEntry);
+            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
+                    actualEntry instanceof PrivateKeyEntry);
+
+            PrivateKeyEntry actualPrivEntry = (PrivateKeyEntry) actualEntry;
+            assertPrivateKeyEntryEquals(actualPrivEntry, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
+        }
+
+        // Replace with PrivateKeyEntry that has no chain
+        {
+            KeyFactory keyFact = KeyFactory.getInstance("RSA");
+            PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
+            final Certificate[] expectedChain = new Certificate[1];
+            expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+
+            PrivateKeyEntry expectedPrivEntry = new PrivateKeyEntry(expectedKey, expectedChain);
+
+            mKeyStore.setEntry(TEST_ALIAS_1, expectedPrivEntry, null);
+
+            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+            assertNotNull("Retrieved entry should exist", actualEntry);
+            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
+                    actualEntry instanceof PrivateKeyEntry);
+
+            PrivateKeyEntry actualPrivEntry = (PrivateKeyEntry) actualEntry;
+            assertPrivateKeyEntryEquals(actualPrivEntry, FAKE_KEY_1, FAKE_USER_1, null);
+        }
+    }
+
+    public void testKeyStore_SetEntry_CAEntry_Overwrites_CAEntry_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        final CertificateFactory f = CertificateFactory.getInstance("X.509");
+
+        // Insert TrustedCertificateEntry
+        {
+            final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+            TrustedCertificateEntry expectedCertEntry = new TrustedCertificateEntry(caCert);
+            mKeyStore.setEntry(TEST_ALIAS_1, expectedCertEntry, null);
+
+            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+            assertNotNull("Retrieved entry should exist", actualEntry);
+            assertTrue("Retrieved entry should be of type TrustedCertificateEntry",
+                    actualEntry instanceof TrustedCertificateEntry);
+            TrustedCertificateEntry actualCertEntry = (TrustedCertificateEntry) actualEntry;
+            assertEquals("Stored and retrieved certificates should be the same",
+                    expectedCertEntry.getTrustedCertificate(),
+                    actualCertEntry.getTrustedCertificate());
+        }
+
+        // Replace with TrustedCertificateEntry of USER
+        {
+            final Certificate userCert = f
+                    .generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+
+            TrustedCertificateEntry expectedUserEntry = new TrustedCertificateEntry(userCert);
+            mKeyStore.setEntry(TEST_ALIAS_1, expectedUserEntry, null);
+
+            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+            assertNotNull("Retrieved entry should exist", actualEntry);
+            assertTrue("Retrieved entry should be of type TrustedCertificateEntry",
+                    actualEntry instanceof TrustedCertificateEntry);
+            TrustedCertificateEntry actualUserEntry = (TrustedCertificateEntry) actualEntry;
+            assertEquals("Stored and retrieved certificates should be the same",
+                    expectedUserEntry.getTrustedCertificate(),
+                    actualUserEntry.getTrustedCertificate());
+        }
+    }
+
+    public void testKeyStore_SetKeyEntry_ProtectedKey_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        final CertificateFactory f = CertificateFactory.getInstance("X.509");
+
+        final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+        KeyFactory keyFact = KeyFactory.getInstance("RSA");
+        PrivateKey privKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
+        final Certificate[] chain = new Certificate[2];
+        chain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+        chain[1] = caCert;
+
+        try {
+            mKeyStore.setKeyEntry(TEST_ALIAS_1, privKey, "foo".toCharArray(), chain);
+            fail("Should fail when a password is specified");
+        } catch (KeyStoreException success) {
+        }
+    }
+
+    public void testKeyStore_SetKeyEntry_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        final CertificateFactory f = CertificateFactory.getInstance("X.509");
+
+        final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+        KeyFactory keyFact = KeyFactory.getInstance("RSA");
+        PrivateKey privKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
+        final Certificate[] chain = new Certificate[2];
+        chain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+        chain[1] = caCert;
+
+        mKeyStore.setKeyEntry(TEST_ALIAS_1, privKey, null, chain);
+
+        Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+        assertNotNull("Retrieved entry should exist", actualEntry);
+
+        assertTrue("Retrieved entry should be of type PrivateKeyEntry",
+                actualEntry instanceof PrivateKeyEntry);
+
+        PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
+
+        assertPrivateKeyEntryEquals(actual, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
+    }
+
+    public void testKeyStore_SetKeyEntry_Replaced_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        final CertificateFactory f = CertificateFactory.getInstance("X.509");
+
+        final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_CA_1));
+
+        // Insert initial key
+        {
+            KeyFactory keyFact = KeyFactory.getInstance("RSA");
+            PrivateKey privKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
+            final Certificate[] chain = new Certificate[2];
+            chain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+            chain[1] = caCert;
+
+            mKeyStore.setKeyEntry(TEST_ALIAS_1, privKey, null, chain);
+
+            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+            assertNotNull("Retrieved entry should exist", actualEntry);
+
+            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
+                    actualEntry instanceof PrivateKeyEntry);
+
+            PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
+
+            assertPrivateKeyEntryEquals(actual, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
+        }
+
+        // TODO make a separate key
+        // Replace key
+        {
+            KeyFactory keyFact = KeyFactory.getInstance("RSA");
+            PrivateKey privKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_KEY_1));
+            final Certificate[] chain = new Certificate[2];
+            chain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_USER_1));
+            chain[1] = caCert;
+
+            mKeyStore.setKeyEntry(TEST_ALIAS_1, privKey, null, chain);
+
+            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
+            assertNotNull("Retrieved entry should exist", actualEntry);
+
+            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
+                    actualEntry instanceof PrivateKeyEntry);
+
+            PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
+
+            assertPrivateKeyEntryEquals(actual, FAKE_KEY_1, FAKE_USER_1, FAKE_CA_1);
+        }
+    }
+
+    public void testKeyStore_Size_Success() throws Exception {
+        mKeyStore.load(null, null);
+
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_CA_1));
+
+        assertEquals("The keystore size should match expected", 1, mKeyStore.size());
+        assertAliases(new String[] { TEST_ALIAS_1 });
+
+        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_CA_1));
+
+        assertEquals("The keystore size should match expected", 2, mKeyStore.size());
+        assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2 });
+
+        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_3));
+
+        assertEquals("The keystore size should match expected", 3, mKeyStore.size());
+        assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2, TEST_ALIAS_3 });
+
+        assertTrue(mAndroidKeyStore.delete(Credentials.CA_CERTIFICATE + TEST_ALIAS_1));
+
+        assertEquals("The keystore size should match expected", 2, mKeyStore.size());
+        assertAliases(new String[] { TEST_ALIAS_2, TEST_ALIAS_3 });
+
+        assertTrue(mAndroidKeyStore.delKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_3));
+
+        assertEquals("The keystore size should match expected", 1, mKeyStore.size());
+        assertAliases(new String[] { TEST_ALIAS_2 });
+    }
+
+    public void testKeyStore_Store_LoadStoreParam_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        try {
+            mKeyStore.store(null);
+            fail("Should throw UnsupportedOperationException when trying to store");
+        } catch (UnsupportedOperationException success) {
+        }
+    }
+
+    public void testKeyStore_Load_InputStreamSupplied_Failure() throws Exception {
+        byte[] buf = "FAKE KEYSTORE".getBytes();
+        ByteArrayInputStream is = new ByteArrayInputStream(buf);
+
+        try {
+            mKeyStore.load(is, null);
+            fail("Should throw IllegalArgumentException when InputStream is supplied");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testKeyStore_Load_PasswordSupplied_Failure() throws Exception {
+        try {
+            mKeyStore.load(null, "password".toCharArray());
+            fail("Should throw IllegalArgumentException when password is supplied");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testKeyStore_Store_OutputStream_Failure() throws Exception {
+        mKeyStore.load(null, null);
+
+        OutputStream sink = new ByteArrayOutputStream();
+        try {
+            mKeyStore.store(sink, null);
+            fail("Should throw UnsupportedOperationException when trying to store");
+        } catch (UnsupportedOperationException success) {
+        }
+
+        try {
+            mKeyStore.store(sink, "blah".toCharArray());
+            fail("Should throw UnsupportedOperationException when trying to store");
+        } catch (UnsupportedOperationException success) {
+        }
+    }
+}
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index 32cd6e2..07a2d7b 100755
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -14,14 +14,16 @@
  * limitations under the License.
  */
 
-package android.security.tests;
+package android.security;
 
 import android.app.Activity;
 import android.security.KeyStore;
 import android.test.ActivityUnitTestCase;
+import android.test.AssertionFailedError;
 import android.test.suitebuilder.annotation.MediumTest;
 import java.nio.charset.Charsets;
 import java.util.Arrays;
+import java.util.Date;
 import java.util.HashSet;
 
 /**
@@ -29,7 +31,11 @@
  *
  * Running the test suite:
  *
- *  adb shell am instrument -w android.security.tests/.KeyStoreTestRunner
+ *  runtest keystore-unit
+ *
+ * Or this individual test case:
+ *
+ *  runtest --path frameworks/base/keystore/tests/src/android/security/KeyStoreTest.java
  */
 @MediumTest
 public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
@@ -399,4 +405,52 @@
         assertFalse("Should fail to ungrant key to other user second time",
                 mKeyStore.ungrant(TEST_KEYNAME, 0));
     }
+
+    /**
+     * The amount of time to allow before and after expected time for variance
+     * in timing tests.
+     */
+    private static final long SLOP_TIME_MILLIS = 15000L;
+
+    public void testGetmtime_Success() throws Exception {
+        assertTrue("Password should work for keystore",
+                mKeyStore.password(TEST_PASSWD));
+
+        assertTrue("Should be able to import key when unlocked",
+                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
+
+        long now = System.currentTimeMillis();
+        long actual = mKeyStore.getmtime(TEST_KEYNAME);
+
+        long expectedAfter = now - SLOP_TIME_MILLIS;
+        long expectedBefore = now + SLOP_TIME_MILLIS;
+
+        assertLessThan("Time should be close to current time", expectedBefore, actual);
+        assertGreaterThan("Time should be close to current time", expectedAfter, actual);
+    }
+
+    private static void assertLessThan(String explanation, long expectedBefore, long actual) {
+        if (actual >= expectedBefore) {
+            throw new AssertionFailedError(explanation + ": actual=" + actual
+                    + ", expected before: " + expectedBefore);
+        }
+    }
+
+    private static void assertGreaterThan(String explanation, long expectedAfter, long actual) {
+        if (actual <= expectedAfter) {
+            throw new AssertionFailedError(explanation + ": actual=" + actual
+                    + ", expected after: " + expectedAfter);
+        }
+    }
+
+    public void testGetmtime_NonExist_Failure() throws Exception {
+        assertTrue("Password should work for keystore",
+                mKeyStore.password(TEST_PASSWD));
+
+        assertTrue("Should be able to import key when unlocked",
+                mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
+
+        assertEquals("-1 should be returned for non-existent key",
+                -1L, mKeyStore.getmtime(TEST_KEYNAME2));
+    }
 }
diff --git a/keystore/tests/src/android/security/KeyStoreTestRunner.java b/keystore/tests/src/android/security/KeyStoreTestRunner.java
deleted file mode 100644
index c56eeb9..0000000
--- a/keystore/tests/src/android/security/KeyStoreTestRunner.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.tests;
-
-import junit.framework.TestSuite;
-
-import android.test.InstrumentationTestRunner;
-import android.test.InstrumentationTestSuite;
-
-/**
- * Instrumentation Test Runner for all KeyStore unit tests.
- *
- * Running all tests:
- *
- *   runtest keystore-unit
- * or
- *   adb shell am instrument -w android.security.tests/.KeyStoreTestRunner
- */
-
-public class KeyStoreTestRunner extends InstrumentationTestRunner {
-
-    @Override
-    public TestSuite getAllTests() {
-        TestSuite suite = new InstrumentationTestSuite(this);
-        suite.addTestSuite(android.security.tests.KeyStoreTest.class);
-        suite.addTestSuite(android.security.tests.SystemKeyStoreTest.class);
-        return suite;
-    }
-
-    @Override
-    public ClassLoader getLoader() {
-        return KeyStoreTestRunner.class.getClassLoader();
-    }
-}
diff --git a/keystore/tests/src/android/security/SystemKeyStoreTest.java b/keystore/tests/src/android/security/SystemKeyStoreTest.java
index a4d744b..ecf7cbc 100644
--- a/keystore/tests/src/android/security/SystemKeyStoreTest.java
+++ b/keystore/tests/src/android/security/SystemKeyStoreTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security.tests;
+package android.security;
 
 import android.app.Activity;
 import android.security.SystemKeyStore;
@@ -26,7 +26,11 @@
  *
  * Running the test suite:
  *
- *  adb shell am instrument -w android.security.tests/.KeyStoreTestRunner
+ *  runtest keystore-unit
+ *
+ * Or this individual test case:
+ *
+ *  runtest --path frameworks/base/keystore/tests/src/android/security/SystemKeyStoreTest.java
  */
 @MediumTest
 public class SystemKeyStoreTest extends ActivityUnitTestCase<Activity> {
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 95fc2c5..2de70d462 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -1699,7 +1699,9 @@
     addFloat(hOffset);
     addFloat(vOffset);
     paint->setAntiAlias(true);
-    addPaint(paint);
+    SkPaint* addedPaint = addPaint(paint);
+    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
+    fontRenderer.precache(addedPaint, text, count);
     return DrawGlInfo::kStatusDone;
 }
 
@@ -1711,7 +1713,9 @@
     addInt(count);
     addFloats(positions, count * 2);
     paint->setAntiAlias(true);
-    addPaint(paint);
+    SkPaint* addedPaint = addPaint(paint);
+    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
+    fontRenderer.precache(addedPaint, text, count);
     return DrawGlInfo::kStatusDone;
 }
 
@@ -1742,7 +1746,11 @@
     addFloat(x);
     addFloat(y);
     addFloats(positions, count * 2);
-    addPaint(paint);
+    SkPaint* addedPaint = addPaint(paint);
+    if (!reject) {
+        FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(addedPaint);
+        fontRenderer.precache(addedPaint, text, count);
+    }
     addFloat(length);
     addSkip(location);
     return DrawGlInfo::kStatusDone;
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 60a40c6..c8b3e47 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -770,10 +770,10 @@
         addInt((int) pathCopy);
     }
 
-    inline void addPaint(SkPaint* paint) {
+    inline SkPaint* addPaint(SkPaint* paint) {
         if (!paint) {
             addInt((int) NULL);
-            return;
+            return paint;
         }
 
         SkPaint* paintCopy = mPaintMap.valueFor(paint);
@@ -785,6 +785,8 @@
         }
 
         addInt((int) paintCopy);
+
+        return paintCopy;
     }
 
     inline void addDisplayList(DisplayList* displayList) {
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index ccddd91..27e198c 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -37,27 +37,153 @@
 #define DEFAULT_TEXT_CACHE_WIDTH 1024
 #define DEFAULT_TEXT_CACHE_HEIGHT 256
 #define MAX_TEXT_CACHE_WIDTH 2048
-#define TEXTURE_BORDER_SIZE 1
+#define CACHE_BLOCK_ROUNDING_SIZE 4
 
 #define AUTO_KERN(prev, next) (((next) - (prev) + 32) >> 6 << 16)
 
 ///////////////////////////////////////////////////////////////////////////////
-// CacheTextureLine
+// CacheBlock
 ///////////////////////////////////////////////////////////////////////////////
 
-bool CacheTextureLine::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
-    if (glyph.fHeight + TEXTURE_BORDER_SIZE > mMaxHeight) {
+/**
+ * Insert new block into existing linked list of blocks. Blocks are sorted in increasing-width
+ * order, except for the final block (the remainder space at the right, since we fill from the
+ * left).
+ */
+CacheBlock* CacheBlock::insertBlock(CacheBlock* head, CacheBlock *newBlock) {
+#if DEBUG_FONT_RENDERER
+    ALOGD("insertBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
+            newBlock, newBlock->mX, newBlock->mY,
+            newBlock->mWidth, newBlock->mHeight);
+#endif
+    CacheBlock *currBlock = head;
+    CacheBlock *prevBlock = NULL;
+    while (currBlock && currBlock->mY != TEXTURE_BORDER_SIZE) {
+        if (newBlock->mWidth < currBlock->mWidth) {
+            newBlock->mNext = currBlock;
+            newBlock->mPrev = prevBlock;
+            currBlock->mPrev = newBlock;
+            if (prevBlock) {
+                prevBlock->mNext = newBlock;
+                return head;
+            } else {
+                return newBlock;
+            }
+        }
+        prevBlock = currBlock;
+        currBlock = currBlock->mNext;
+    }
+    // new block larger than all others - insert at end (but before the remainder space, if there)
+    newBlock->mNext = currBlock;
+    newBlock->mPrev = prevBlock;
+    if (currBlock) {
+        currBlock->mPrev = newBlock;
+    }
+    if (prevBlock) {
+        prevBlock->mNext = newBlock;
+        return head;
+    } else {
+        return newBlock;
+    }
+}
+
+CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock *blockToRemove) {
+#if DEBUG_FONT_RENDERER
+    ALOGD("removeBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
+            blockToRemove, blockToRemove->mX, blockToRemove->mY,
+            blockToRemove->mWidth, blockToRemove->mHeight);
+#endif
+    CacheBlock* newHead = head;
+    CacheBlock* nextBlock = blockToRemove->mNext;
+    CacheBlock* prevBlock = blockToRemove->mPrev;
+    if (prevBlock) {
+        prevBlock->mNext = nextBlock;
+    } else {
+        newHead = nextBlock;
+    }
+    if (nextBlock) {
+        nextBlock->mPrev = prevBlock;
+    }
+    delete blockToRemove;
+    return newHead;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CacheTexture
+///////////////////////////////////////////////////////////////////////////////
+
+bool CacheTexture::fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY) {
+    if (glyph.fHeight + TEXTURE_BORDER_SIZE > mHeight) {
         return false;
     }
 
-    if (mCurrentCol + glyph.fWidth + TEXTURE_BORDER_SIZE * 2 < mMaxWidth) {
-        *retOriginX = mCurrentCol + TEXTURE_BORDER_SIZE;
-        *retOriginY = mCurrentRow + TEXTURE_BORDER_SIZE;
-        mCurrentCol += glyph.fWidth + TEXTURE_BORDER_SIZE * 2;
-        mDirty = true;
-        return true;
+    uint16_t glyphW = glyph.fWidth + TEXTURE_BORDER_SIZE;
+    uint16_t glyphH = glyph.fHeight + TEXTURE_BORDER_SIZE;
+    // roundedUpW equals glyphW to the next multiple of CACHE_BLOCK_ROUNDING_SIZE.
+    // This columns for glyphs that are close but not necessarily exactly the same size. It trades
+    // off the loss of a few pixels for some glyphs against the ability to store more glyphs
+    // of varying sizes in one block.
+    uint16_t roundedUpW =
+            (glyphW + CACHE_BLOCK_ROUNDING_SIZE - 1) & -CACHE_BLOCK_ROUNDING_SIZE;
+    CacheBlock *cacheBlock = mCacheBlocks;
+    while (cacheBlock) {
+        // Store glyph in this block iff: it fits the block's remaining space and:
+        // it's the remainder space (mY == 0) or there's only enough height for this one glyph
+        // or it's within ROUNDING_SIZE of the block width
+        if (roundedUpW <= cacheBlock->mWidth && glyphH <= cacheBlock->mHeight &&
+                (cacheBlock->mY == TEXTURE_BORDER_SIZE ||
+                        (cacheBlock->mWidth - roundedUpW < CACHE_BLOCK_ROUNDING_SIZE))) {
+            if (cacheBlock->mHeight - glyphH < glyphH) {
+                // Only enough space for this glyph - don't bother rounding up the width
+                roundedUpW = glyphW;
+            }
+            *retOriginX = cacheBlock->mX;
+            *retOriginY = cacheBlock->mY;
+            // If this is the remainder space, create a new cache block for this column. Otherwise,
+            // adjust the info about this column.
+            if (cacheBlock->mY == TEXTURE_BORDER_SIZE) {
+                uint16_t oldX = cacheBlock->mX;
+                // Adjust remainder space dimensions
+                cacheBlock->mWidth -= roundedUpW;
+                cacheBlock->mX += roundedUpW;
+                if (mHeight - glyphH >= glyphH) {
+                    // There's enough height left over to create a new CacheBlock
+                    CacheBlock *newBlock = new CacheBlock(oldX, glyphH + TEXTURE_BORDER_SIZE,
+                            roundedUpW, mHeight - glyphH - TEXTURE_BORDER_SIZE);
+#if DEBUG_FONT_RENDERER
+                    ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d",
+                            newBlock, newBlock->mX, newBlock->mY,
+                            newBlock->mWidth, newBlock->mHeight);
+#endif
+                    mCacheBlocks = CacheBlock::insertBlock(mCacheBlocks, newBlock);
+                }
+            } else {
+                // Insert into current column and adjust column dimensions
+                cacheBlock->mY += glyphH;
+                cacheBlock->mHeight -= glyphH;
+#if DEBUG_FONT_RENDERER
+                ALOGD("fitBitmap: Added to existing block: this, x, y, w, h = %p, %d, %d, %d, %d",
+                        cacheBlock, cacheBlock->mX, cacheBlock->mY,
+                        cacheBlock->mWidth, cacheBlock->mHeight);
+#endif
+            }
+            if (cacheBlock->mHeight < fmin(glyphH, glyphW)) {
+                // If remaining space in this block is too small to be useful, remove it
+                mCacheBlocks = CacheBlock::removeBlock(mCacheBlocks, cacheBlock);
+            }
+            mDirty = true;
+#if DEBUG_FONT_RENDERER
+            ALOGD("fitBitmap: current block list:");
+            mCacheBlocks->output();
+#endif
+            ++mNumGlyphs;
+            return true;
+        }
+        cacheBlock = cacheBlock->mNext;
     }
-
+#if DEBUG_FONT_RENDERER
+    ALOGD("fitBitmap: returning false for glyph of size %d, %d", glyphW, glyphH);
+#endif
     return false;
 }
 
@@ -87,10 +213,10 @@
     }
 }
 
-void Font::invalidateTextureCache(CacheTextureLine *cacheLine) {
+void Font::invalidateTextureCache(CacheTexture *cacheTexture) {
     for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
         CachedGlyphInfo* cachedGlyph = mCachedGlyphs.valueAt(i);
-        if (cacheLine == NULL || cachedGlyph->mCachedTextureLine == cacheLine) {
+        if (cacheTexture == NULL || cachedGlyph->mCacheTexture == cacheTexture) {
             cachedGlyph->mIsValid = false;
         }
     }
@@ -134,7 +260,7 @@
     mState->appendMeshQuad(nPenX, nPenY, u1, v2,
             nPenX + width, nPenY, u2, v2,
             nPenX + width, nPenY - height, u2, v1,
-            nPenX, nPenY - height, u1, v1, glyph->mCachedTextureLine->mCacheTexture);
+            nPenX, nPenY - height, u1, v1, glyph->mCacheTexture);
 }
 
 void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
@@ -145,7 +271,7 @@
     uint32_t endX = glyph->mStartX + glyph->mBitmapWidth;
     uint32_t endY = glyph->mStartY + glyph->mBitmapHeight;
 
-    CacheTexture *cacheTexture = glyph->mCachedTextureLine->mCacheTexture;
+    CacheTexture *cacheTexture = glyph->mCacheTexture;
     uint32_t cacheWidth = cacheTexture->mWidth;
     const uint8_t* cacheBuffer = cacheTexture->mTexture;
 
@@ -199,7 +325,7 @@
             position->fY + destination[2].fY, u2, v1,
             position->fX + destination[3].fX,
             position->fY + destination[3].fY, u1, v1,
-            glyph->mCachedTextureLine->mCacheTexture);
+            glyph->mCacheTexture);
 }
 
 CachedGlyphInfo* Font::getCachedGlyph(SkPaint* paint, glyph_t textUnit) {
@@ -297,6 +423,27 @@
     render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, positions);
 }
 
+void Font::precache(SkPaint* paint, const char* text, int numGlyphs) {
+
+    if (numGlyphs == 0 || text == NULL) {
+        return;
+    }
+    int glyphsCount = 0;
+
+    while (glyphsCount < numGlyphs) {
+        glyph_t glyph = GET_GLYPH(text);
+
+        // Reached the end of the string
+        if (IS_END_OF_STRING(glyph)) {
+            break;
+        }
+
+        CachedGlyphInfo* cachedGlyph = getCachedGlyph(paint, glyph);
+
+        glyphsCount++;
+    }
+}
+
 void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len,
         int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
         uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) {
@@ -409,8 +556,8 @@
     glyph->mBitmapWidth = skiaGlyph.fWidth;
     glyph->mBitmapHeight = skiaGlyph.fHeight;
 
-    uint32_t cacheWidth = glyph->mCachedTextureLine->mCacheTexture->mWidth;
-    uint32_t cacheHeight = glyph->mCachedTextureLine->mCacheTexture->mHeight;
+    uint32_t cacheWidth = glyph->mCacheTexture->mWidth;
+    uint32_t cacheHeight = glyph->mCacheTexture->mHeight;
 
     glyph->mBitmapMinU = startX / (float) cacheWidth;
     glyph->mBitmapMinV = startY / (float) cacheHeight;
@@ -473,10 +620,6 @@
     mTextMeshPtr = NULL;
     mCurrentCacheTexture = NULL;
     mLastCacheTexture = NULL;
-    mCacheTextureSmall = NULL;
-    mCacheTexture128 = NULL;
-    mCacheTexture256 = NULL;
-    mCacheTexture512 = NULL;
 
     mLinearFiltering = false;
 
@@ -512,10 +655,10 @@
 }
 
 FontRenderer::~FontRenderer() {
-    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
-        delete mCacheLines[i];
+    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
+        delete mCacheTextures[i];
     }
-    mCacheLines.clear();
+    mCacheTextures.clear();
 
     if (mInitialized) {
         // Unbinding the buffer shouldn't be necessary but it crashes with some drivers
@@ -523,10 +666,6 @@
         glDeleteBuffers(1, &mIndexBufferID);
 
         delete[] mTextMeshPtr;
-        delete mCacheTextureSmall;
-        delete mCacheTexture128;
-        delete mCacheTexture256;
-        delete mCacheTexture512;
     }
 
     Vector<Font*> fontsToDereference = mActiveFonts;
@@ -545,9 +684,22 @@
         mActiveFonts[i]->invalidateTextureCache();
     }
 
-    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
-        mCacheLines[i]->mCurrentCol = 0;
+    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
+        mCacheTextures[i]->init();
     }
+
+    #if DEBUG_FONT_RENDERER
+    uint16_t totalGlyphs = 0;
+    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
+        totalGlyphs += mCacheTextures[i]->mNumGlyphs;
+        // Erase caches, just as a debugging facility
+        if (mCacheTextures[i]->mTexture) {
+            memset(mCacheTextures[i]->mTexture, 0,
+                    mCacheTextures[i]->mWidth * mCacheTextures[i]->mHeight);
+        }
+    }
+    ALOGD("Flushing caches: glyphs cached = %d", totalGlyphs);
+#endif
 }
 
 void FontRenderer::deallocateTextureMemory(CacheTexture *cacheTexture) {
@@ -560,29 +712,17 @@
 }
 
 void FontRenderer::flushLargeCaches() {
-    if ((!mCacheTexture128 || !mCacheTexture128->mTexture) &&
-            (!mCacheTexture256 || !mCacheTexture256->mTexture) &&
-            (!mCacheTexture512 || !mCacheTexture512->mTexture)) {
-        // Typical case; no large glyph caches allocated
-        return;
-    }
-
-    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
-        CacheTextureLine* cacheLine = mCacheLines[i];
-        if ((cacheLine->mCacheTexture == mCacheTexture128 ||
-                cacheLine->mCacheTexture == mCacheTexture256 ||
-                cacheLine->mCacheTexture == mCacheTexture512) &&
-                cacheLine->mCacheTexture->mTexture != NULL) {
-            cacheLine->mCurrentCol = 0;
-            for (uint32_t i = 0; i < mActiveFonts.size(); i++) {
-                mActiveFonts[i]->invalidateTextureCache(cacheLine);
+    // Start from 1; don't deallocate smallest/default texture
+    for (uint32_t i = 1; i < mCacheTextures.size(); i++) {
+        CacheTexture* cacheTexture = mCacheTextures[i];
+        if (cacheTexture->mTexture != NULL) {
+            cacheTexture->init();
+            for (uint32_t j = 0; j < mActiveFonts.size(); j++) {
+                mActiveFonts[j]->invalidateTextureCache(cacheTexture);
             }
+            deallocateTextureMemory(cacheTexture);
         }
     }
-
-    deallocateTextureMemory(mCacheTexture128);
-    deallocateTextureMemory(mCacheTexture256);
-    deallocateTextureMemory(mCacheTexture512);
 }
 
 void FontRenderer::allocateTextureMemory(CacheTexture* cacheTexture) {
@@ -610,12 +750,25 @@
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 }
 
+CacheTexture* FontRenderer::cacheBitmapInTexture(const SkGlyph& glyph,
+        uint32_t* startX, uint32_t* startY) {
+    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
+        if (mCacheTextures[i]->fitBitmap(glyph, startX, startY)) {
+            return mCacheTextures[i];
+        }
+    }
+    // Could not fit glyph into current cache textures
+    return NULL;
+}
+
 void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
         uint32_t* retOriginX, uint32_t* retOriginY) {
+    checkInit();
     cachedGlyph->mIsValid = false;
     // If the glyph is too tall, don't cache it
-    if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 > mCacheLines[mCacheLines.size() - 1]->mMaxHeight) {
-        ALOGE("Font size to large to fit in cache. width, height = %i, %i",
+    if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
+                mCacheTextures[mCacheTextures.size() - 1]->mHeight) {
+        ALOGE("Font size too large to fit in cache. width, height = %i, %i",
                 (int) glyph.fWidth, (int) glyph.fHeight);
         return;
     }
@@ -624,36 +777,22 @@
     uint32_t startX = 0;
     uint32_t startY = 0;
 
-    bool bitmapFit = false;
-    CacheTextureLine *cacheLine;
-    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
-        bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
-        if (bitmapFit) {
-            cacheLine = mCacheLines[i];
-            break;
-        }
-    }
+    CacheTexture* cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY);
 
     // If the new glyph didn't fit, flush the state so far and invalidate everything
-    if (!bitmapFit) {
+    if (!cacheTexture) {
         flushAllAndInvalidate();
 
         // Try to fit it again
-        for (uint32_t i = 0; i < mCacheLines.size(); i++) {
-            bitmapFit = mCacheLines[i]->fitBitmap(glyph, &startX, &startY);
-            if (bitmapFit) {
-                cacheLine = mCacheLines[i];
-                break;
-            }
-        }
+        cacheTexture = cacheBitmapInTexture(glyph, &startX, &startY);
 
         // if we still don't fit, something is wrong and we shouldn't draw
-        if (!bitmapFit) {
+        if (!cacheTexture) {
             return;
         }
     }
 
-    cachedGlyph->mCachedTextureLine = cacheLine;
+    cachedGlyph->mCacheTexture = cacheTexture;
 
     *retOriginX = startX;
     *retOriginY = startY;
@@ -661,9 +800,8 @@
     uint32_t endX = startX + glyph.fWidth;
     uint32_t endY = startY + glyph.fHeight;
 
-    uint32_t cacheWidth = cacheLine->mMaxWidth;
+    uint32_t cacheWidth = cacheTexture->mWidth;
 
-    CacheTexture* cacheTexture = cacheLine->mCacheTexture;
     if (!cacheTexture->mTexture) {
         // Large-glyph texture memory is allocated only as needed
         allocateTextureMemory(cacheTexture);
@@ -716,17 +854,10 @@
 }
 
 void FontRenderer::initTextTexture() {
-    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
-        delete mCacheLines[i];
+    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
+        delete mCacheTextures[i];
     }
-    mCacheLines.clear();
-
-    if (mCacheTextureSmall) {
-        delete mCacheTextureSmall;
-        delete mCacheTexture128;
-        delete mCacheTexture256;
-        delete mCacheTexture512;
-    }
+    mCacheTextures.clear();
 
     // Next, use other, separate caches for large glyphs.
     uint16_t maxWidth = 0;
@@ -738,35 +869,12 @@
         maxWidth = MAX_TEXT_CACHE_WIDTH;
     }
 
-    mCacheTextureSmall = createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true);
-    mCacheTexture128 = createCacheTexture(maxWidth, 256, false);
-    mCacheTexture256 = createCacheTexture(maxWidth, 256, false);
-    mCacheTexture512 = createCacheTexture(maxWidth, 512, false);
-    mCurrentCacheTexture = mCacheTextureSmall;
-
     mUploadTexture = false;
-    // Split up our default cache texture into lines of certain widths
-    int nextLine = 0;
-    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 18, nextLine, 0, mCacheTextureSmall));
-    nextLine += mCacheLines.top()->mMaxHeight;
-    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall));
-    nextLine += mCacheLines.top()->mMaxHeight;
-    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 26, nextLine, 0, mCacheTextureSmall));
-    nextLine += mCacheLines.top()->mMaxHeight;
-    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall));
-    nextLine += mCacheLines.top()->mMaxHeight;
-    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 34, nextLine, 0, mCacheTextureSmall));
-    nextLine += mCacheLines.top()->mMaxHeight;
-    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, 42, nextLine, 0, mCacheTextureSmall));
-    nextLine += mCacheLines.top()->mMaxHeight;
-    mCacheLines.push(new CacheTextureLine(mSmallCacheWidth, mSmallCacheHeight - nextLine,
-            nextLine, 0, mCacheTextureSmall));
-
-    //  The first cache is split into 2 lines of height 128, the rest have just one cache line.
-    mCacheLines.push(new CacheTextureLine(maxWidth, 128, 0, 0, mCacheTexture128));
-    mCacheLines.push(new CacheTextureLine(maxWidth, 128, 128, 0, mCacheTexture128));
-    mCacheLines.push(new CacheTextureLine(maxWidth, 256, 0, 0, mCacheTexture256));
-    mCacheLines.push(new CacheTextureLine(maxWidth, 512, 0, 0, mCacheTexture512));
+    mCacheTextures.push(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, true));
+    mCacheTextures.push(createCacheTexture(maxWidth, 256, false));
+    mCacheTextures.push(createCacheTexture(maxWidth, 256, false));
+    mCacheTextures.push(createCacheTexture(maxWidth, 512, false));
+    mCurrentCacheTexture = mCacheTextures[0];
 }
 
 // Avoid having to reallocate memory and render quad by quad
@@ -821,26 +929,28 @@
 
     Caches& caches = Caches::getInstance();
     GLuint lastTextureId = 0;
-    // Iterate over all the cache lines and see which ones need to be updated
-    for (uint32_t i = 0; i < mCacheLines.size(); i++) {
-        CacheTextureLine* cl = mCacheLines[i];
-        if (cl->mDirty && cl->mCacheTexture->mTexture != NULL) {
-            CacheTexture* cacheTexture = cl->mCacheTexture;
+    // Iterate over all the cache textures and see which ones need to be updated
+    for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
+        CacheTexture* cacheTexture = mCacheTextures[i];
+        if (cacheTexture->mDirty && cacheTexture->mTexture != NULL) {
             uint32_t xOffset = 0;
-            uint32_t yOffset = cl->mCurrentRow;
-            uint32_t width   = cl->mMaxWidth;
-            uint32_t height  = cl->mMaxHeight;
-            void* textureData = cacheTexture->mTexture + (yOffset * width);
+            uint32_t width   = cacheTexture->mWidth;
+            uint32_t height  = cacheTexture->mHeight;
+            void* textureData = cacheTexture->mTexture;
 
             if (cacheTexture->mTextureId != lastTextureId) {
                 caches.activeTexture(0);
                 glBindTexture(GL_TEXTURE_2D, cacheTexture->mTextureId);
                 lastTextureId = cacheTexture->mTextureId;
             }
-            glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, width, height,
+#if DEBUG_FONT_RENDERER
+            ALOGD("glTextSubimage for cacheTexture %d: xOff, width height = %d, %d, %d",
+                    i, xOffset, width, height);
+#endif
+            glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, 0, width, height,
                     GL_ALPHA, GL_UNSIGNED_BYTE, textureData);
 
-            cl->mDirty = false;
+            cacheTexture->mDirty = false;
         }
     }
 
@@ -960,43 +1070,7 @@
     }
 }
 
-uint32_t FontRenderer::getRemainingCacheCapacity() {
-    uint32_t remainingCapacity = 0;
-    float totalPixels = 0;
-
-    //avoid divide by zero if the size is 0
-    if (mCacheLines.size() == 0) {
-        return 0;
-    }
-    for(uint32_t i = 0; i < mCacheLines.size(); i ++) {
-         remainingCapacity += (mCacheLines[i]->mMaxWidth - mCacheLines[i]->mCurrentCol);
-         totalPixels += mCacheLines[i]->mMaxWidth;
-    }
-    remainingCapacity = (remainingCapacity * 100) / totalPixels;
-    return remainingCapacity;
-}
-
-void FontRenderer::precacheLatin(SkPaint* paint) {
-    // Remaining capacity is measured in %
-    uint32_t remainingCapacity = getRemainingCacheCapacity();
-    uint32_t precacheIndex = 0;
-
-    // We store a string with letters in a rough frequency of occurrence
-    String16 l("eisarntolcdugpmhbyfvkwzxjq EISARNTOLCDUGPMHBYFVKWZXJQ,.?!()-+@;:'0123456789");
-
-    size_t size = l.size();
-    uint16_t latin[size];
-    paint->utfToGlyphs(l.string(), SkPaint::kUTF16_TextEncoding, size * sizeof(char16_t), latin);
-
-    while (remainingCapacity > 25 && precacheIndex < size) {
-        mCurrentFont->getCachedGlyph(paint, TO_GLYPH(latin[precacheIndex]));
-        remainingCapacity = getRemainingCacheCapacity();
-        precacheIndex++;
-    }
-}
-
 void FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) {
-    uint32_t currentNumFonts = mActiveFonts.size();
     int flags = 0;
     if (paint->isFakeBoldText()) {
         flags |= Font::kFakeBold;
@@ -1012,12 +1086,6 @@
     mCurrentFont = Font::create(this, fontId, fontSize, flags, italicStyle,
             scaleX, style, strokeWidth);
 
-    const float maxPrecacheFontSize = 40.0f;
-    bool isNewFont = currentNumFonts != mActiveFonts.size();
-
-    if (isNewFont && fontSize <= maxPrecacheFontSize) {
-        precacheLatin(paint);
-    }
 }
 
 FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text,
@@ -1084,6 +1152,25 @@
     }
 }
 
+void FontRenderer::precache(SkPaint* paint, const char* text, int numGlyphs) {
+    int flags = 0;
+    if (paint->isFakeBoldText()) {
+        flags |= Font::kFakeBold;
+    }
+    const float skewX = paint->getTextSkewX();
+    uint32_t italicStyle = *(uint32_t*) &skewX;
+    const float scaleXFloat = paint->getTextScaleX();
+    uint32_t scaleX = *(uint32_t*) &scaleXFloat;
+    SkPaint::Style style = paint->getStyle();
+    const float strokeWidthFloat = paint->getStrokeWidth();
+    uint32_t strokeWidth = *(uint32_t*) &strokeWidthFloat;
+    float fontSize = paint->getTextSize();
+    Font* font = Font::create(this, SkTypeface::UniqueID(paint->getTypeface()),
+            fontSize, flags, italicStyle, scaleX, style, strokeWidth);
+
+    font->precache(paint, text, numGlyphs);
+}
+
 bool FontRenderer::renderText(SkPaint* paint, const Rect* clip, const char *text,
         uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, Rect* bounds) {
     if (!mCurrentFont) {
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 9ed6932..febae17 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -53,17 +53,63 @@
     #define IS_END_OF_STRING(glyph) glyph < 0
 #endif
 
+#define TEXTURE_BORDER_SIZE 1
+
 ///////////////////////////////////////////////////////////////////////////////
 // Declarations
 ///////////////////////////////////////////////////////////////////////////////
 
 class FontRenderer;
 
+/**
+ * CacheBlock is a node in a linked list of current free space areas in a CacheTexture.
+ * Using CacheBlocks enables us to pack the cache from top to bottom as well as left to right.
+ * When we add a glyph to the cache, we see if it fits within one of the existing columns that
+ * have already been started (this is the case if the glyph fits vertically as well as
+ * horizontally, and if its width is sufficiently close to the column width to avoid
+ * sub-optimal packing of small glyphs into wide columns). If there is no column in which the
+ * glyph fits, we check the final node, which is the remaining space in the cache, creating
+ * a new column as appropriate.
+ *
+ * As columns fill up, we remove their CacheBlock from the list to avoid having to check
+ * small blocks in the future.
+ */
+struct CacheBlock {
+    uint16_t mX;
+    uint16_t mY;
+    uint16_t mWidth;
+    uint16_t mHeight;
+    CacheBlock* mNext;
+    CacheBlock* mPrev;
+
+    CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height, bool empty = false):
+        mX(x), mY(y), mWidth(width), mHeight(height), mNext(NULL), mPrev(NULL)
+    {
+    }
+
+    static CacheBlock* insertBlock(CacheBlock* head, CacheBlock *newBlock);
+
+    static CacheBlock* removeBlock(CacheBlock* head, CacheBlock *blockToRemove);
+
+    void output() {
+        CacheBlock *currBlock = this;
+        while (currBlock) {
+            ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d",
+                    currBlock, currBlock->mX, currBlock->mY, currBlock->mWidth, currBlock->mHeight);
+            currBlock = currBlock->mNext;
+        }
+    }
+};
+
 class CacheTexture {
 public:
     CacheTexture(uint16_t width, uint16_t height) :
             mTexture(NULL), mTextureId(0), mWidth(width), mHeight(height),
-            mLinearFiltering(false) { }
+            mLinearFiltering(false), mDirty(false), mNumGlyphs(0) {
+        mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
+                mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
+    }
+
     ~CacheTexture() {
         if (mTexture) {
             delete[] mTexture;
@@ -71,35 +117,36 @@
         if (mTextureId) {
             glDeleteTextures(1, &mTextureId);
         }
+        reset();
     }
 
+    void reset() {
+        // Delete existing cache blocks
+        while (mCacheBlocks != NULL) {
+            CacheBlock* tmpBlock = mCacheBlocks;
+            mCacheBlocks = mCacheBlocks->mNext;
+            delete tmpBlock;
+        }
+        mNumGlyphs = 0;
+    }
+
+    void init() {
+        // reset, then create a new remainder space to start again
+        reset();
+        mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
+                mWidth - TEXTURE_BORDER_SIZE, mHeight - TEXTURE_BORDER_SIZE, true);
+    }
+
+    bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY);
+
     uint8_t* mTexture;
     GLuint mTextureId;
     uint16_t mWidth;
     uint16_t mHeight;
     bool mLinearFiltering;
-};
-
-class CacheTextureLine {
-public:
-    CacheTextureLine(uint16_t maxWidth, uint16_t maxHeight, uint32_t currentRow,
-            uint32_t currentCol, CacheTexture* cacheTexture):
-                mMaxHeight(maxHeight),
-                mMaxWidth(maxWidth),
-                mCurrentRow(currentRow),
-                mCurrentCol(currentCol),
-                mDirty(false),
-                mCacheTexture(cacheTexture) {
-    }
-
-    bool fitBitmap(const SkGlyph& glyph, uint32_t *retOriginX, uint32_t *retOriginY);
-
-    uint16_t mMaxHeight;
-    uint16_t mMaxWidth;
-    uint32_t mCurrentRow;
-    uint32_t mCurrentCol;
     bool mDirty;
-    CacheTexture* mCacheTexture;
+    uint16_t mNumGlyphs;
+    CacheBlock* mCacheBlocks;
 };
 
 struct CachedGlyphInfo {
@@ -127,7 +174,7 @@
     // Auto-kerning
     SkFixed mLsbDelta;
     SkFixed mRsbDelta;
-    CacheTextureLine* mCachedTextureLine;
+    CacheTexture* mCacheTexture;
 };
 
 
@@ -179,6 +226,8 @@
         MEASURE,
     };
 
+    void precache(SkPaint* paint, const char* text, int numGlyphs);
+
     void render(SkPaint* paint, const char *text, uint32_t start, uint32_t len,
             int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
             uint32_t bitmapW, uint32_t bitmapH, Rect *bounds, const float* positions);
@@ -192,7 +241,7 @@
     // Cache of glyphs
     DefaultKeyedVector<glyph_t, CachedGlyphInfo*> mCachedGlyphs;
 
-    void invalidateTextureCache(CacheTextureLine *cacheLine = NULL);
+    void invalidateTextureCache(CacheTexture *cacheTexture = NULL);
 
     CachedGlyphInfo* cacheGlyph(SkPaint* paint, glyph_t glyph);
     void updateGlyphCache(SkPaint* paint, const SkGlyph& skiaGlyph, CachedGlyphInfo* glyph);
@@ -244,6 +293,9 @@
     }
 
     void setFont(SkPaint* paint, uint32_t fontId, float fontSize);
+
+    void precache(SkPaint* paint, const char* text, int numGlyphs);
+
     // bounds is an out parameter
     bool renderText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
             uint32_t len, int numGlyphs, int x, int y, Rect* bounds);
@@ -293,17 +345,11 @@
 
     uint32_t getCacheSize() const {
         uint32_t size = 0;
-        if (mCacheTextureSmall != NULL && mCacheTextureSmall->mTexture != NULL) {
-            size += mCacheTextureSmall->mWidth * mCacheTextureSmall->mHeight;
-        }
-        if (mCacheTexture128 != NULL && mCacheTexture128->mTexture != NULL) {
-            size += mCacheTexture128->mWidth * mCacheTexture128->mHeight;
-        }
-        if (mCacheTexture256 != NULL && mCacheTexture256->mTexture != NULL) {
-            size += mCacheTexture256->mWidth * mCacheTexture256->mHeight;
-        }
-        if (mCacheTexture512 != NULL && mCacheTexture512->mTexture != NULL) {
-            size += mCacheTexture512->mWidth * mCacheTexture512->mHeight;
+        for (uint32_t i = 0; i < mCacheTextures.size(); i++) {
+            CacheTexture* cacheTexture = mCacheTextures[i];
+            if (cacheTexture != NULL && cacheTexture->mTexture != NULL) {
+                size += cacheTexture->mWidth * cacheTexture->mHeight;
+            }
         }
         return size;
     }
@@ -319,6 +365,7 @@
     CacheTexture* createCacheTexture(int width, int height, bool allocate);
     void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
             uint32_t *retOriginX, uint32_t *retOriginY);
+    CacheTexture* cacheBitmapInTexture(const SkGlyph& glyph, uint32_t* startX, uint32_t* startY);
 
     void flushAllAndInvalidate();
     void initVertexArrayBuffers();
@@ -327,8 +374,6 @@
     void initRender(const Rect* clip, Rect* bounds);
     void finishRender();
 
-    void precacheLatin(SkPaint* paint);
-
     void issueDrawCommand();
     void appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
             float x2, float y2, float u2, float v2,
@@ -346,18 +391,13 @@
     uint32_t mSmallCacheWidth;
     uint32_t mSmallCacheHeight;
 
-    Vector<CacheTextureLine*> mCacheLines;
-    uint32_t getRemainingCacheCapacity();
+    Vector<CacheTexture*> mCacheTextures;
 
     Font* mCurrentFont;
     Vector<Font*> mActiveFonts;
 
     CacheTexture* mCurrentCacheTexture;
     CacheTexture* mLastCacheTexture;
-    CacheTexture* mCacheTextureSmall;
-    CacheTexture* mCacheTexture128;
-    CacheTexture* mCacheTexture256;
-    CacheTexture* mCacheTexture512;
 
     void checkTextureUpdate();
     bool mUploadTexture;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 6639231..849c556 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -250,6 +250,7 @@
     glViewport(0, 0, snapshot->viewport.getWidth(), snapshot->viewport.getHeight());
     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 
+    mCaches.scissorEnabled = glIsEnabled(GL_SCISSOR_TEST);
     mCaches.enableScissor();
     mCaches.resetScissor();
     dirtyClip();
diff --git a/location/java/android/location/Criteria.java b/location/java/android/location/Criteria.java
index 6258a43..68fb4a0 100644
--- a/location/java/android/location/Criteria.java
+++ b/location/java/android/location/Criteria.java
@@ -24,7 +24,9 @@
  * location provider.  Providers maybe ordered according to accuracy,
  * power usage, ability to report altitude, speed,
  * and bearing, and monetary cost.
- * @deprecated {@link LocationRequest} instead
+ *
+ * @deprecated use {@link LocationRequest} instead, and also see notes
+ * at {@link LocationManager}
  */
 @Deprecated
 public class Criteria implements Parcelable {
diff --git a/location/java/android/location/Geofence.java b/location/java/android/location/Geofence.java
index 353a1ca..03cca84 100644
--- a/location/java/android/location/Geofence.java
+++ b/location/java/android/location/Geofence.java
@@ -20,7 +20,11 @@
 import android.os.Parcelable;
 
 /**
- * Represents a Geofence
+ * Represents a geographical boundary, also known as a geofence.
+ *
+ * <p>Currently only circular geofences are supported, but this object
+ * is opaque so could be used in the future to represent polygons or other
+ * shapes.
  */
 public final class Geofence implements Parcelable {
     /** @hide */
@@ -33,6 +37,7 @@
 
     /**
      * Create a horizontal, circular geofence.
+     *
      * @param latitude latitude in degrees
      * @param longitude longitude in degrees
      * @param radius radius in meters
@@ -152,6 +157,9 @@
         return result;
     }
 
+    /**
+     * Two geofences are equal if they have identical properties.
+     */
     @Override
     public boolean equals(Object obj) {
         if (this == obj)
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index a2ce606..f663e0a 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -45,7 +45,7 @@
             in PendingIntent intent, String packageName);
     void removeGeofence(in Geofence fence, in PendingIntent intent, String packageName);
 
-    Location getLastLocation(in LocationRequest request);
+    Location getLastLocation(in LocationRequest request, String packageName);
 
     boolean addGpsStatusListener(IGpsStatusListener listener);
     void removeGpsStatusListener(IGpsStatusListener listener);
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index ece4500..40cb1a8 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -27,15 +27,15 @@
 import java.util.StringTokenizer;
 
 /**
- * A class representing a geographic location sensed at a particular
- * time (a "fix").  A location consists of a latitude and longitude, a
- * UTC timestamp. and optionally information on altitude, speed, and
- * bearing.
+ * A data class representing a geographic location.
  *
- * <p> Information specific to a particular provider or class of
- * providers may be communicated to the application using getExtras,
- * which returns a Bundle of key/value pairs.  Each provider will only
- * provide those entries for which information is available.
+ * <p>A location can consist of a latitude, longitude, timestamp,
+ * and other information such as bearing, altitude and velocity.
+ *
+ * <p>All locations generated by the {@link LocationManager} are
+ * guaranteed to have a valid latitude, longitude, and timestamp
+ * (both UTC time and elapsed real-time since boot), all other
+ * parameters are optional.
  */
 public class Location implements Parcelable {
     /**
@@ -86,20 +86,19 @@
     private float[] mResults = new float[2];
 
     /**
-     * Constructs a new Location.  By default, time, latitude,
-     * longitude, and numSatellites are 0; hasAltitude, hasSpeed, and
-     * hasBearing are false; and there is no extra information.
+     * Construct a new Location with a named provider.
      *
-     * @param provider the name of the location provider that generated this
-     * location fix.
+     * <p>By default time, latitude and longitude are 0, and the location
+     * has no bearing, altitude, speed, accuracy or extras.
+     *
+     * @param provider the name of the provider that generated this location
      */
     public Location(String provider) {
         mProvider = provider;
     }
 
     /**
-     * Constructs a new Location object that is a copy of the given
-     * location.
+     * Construct a new Location object that is copied from an existing one.
      */
     public Location(Location l) {
         set(l);
@@ -447,9 +446,19 @@
     }
 
     /**
-     * Returns the name of the provider that generated this fix,
-     * or null if it is not associated with a provider.
+     * Returns the name of the provider that generated this fix.
+     *
+     * <p class="note">At API version 17 we deprecated {@link LocationProvider}
+     * and all API methods that request a provider by name. The new API methods
+     * will produce locations that could come from different sources, and even
+     * locations that are fused from several sources. So you should generally
+     * not care what provider is associated with a location object.
+     *
+     * @return the provider, or null if it has not been set
+     *
+     * @deprecated locations can now be sourced from many providers, or even fused
      */
+    @Deprecated
     public String getProvider() {
         return mProvider;
     }
@@ -462,16 +471,19 @@
     }
 
     /**
-     * Return the UTC time of this fix, in milliseconds since January 1,
-     * 1970.
+     * Return the UTC time of this fix, in milliseconds since January 1, 1970.
+     *
      * <p>Note that the UTC time on a device is not monotonic: it
      * can jump forwards or backwards unpredictably. So always use
-     * {@link #getElapsedRealtimeNano()} when calculating time deltas.
-     * <p>On the other hand, {@link #getTime()} is useful for presenting
+     * {@link #getElapsedRealtimeNano} when calculating time deltas.
+     *
+     * <p>On the other hand, {@link #getTime} is useful for presenting
      * a human readable time to the user, or for carefully comparing
      * location fixes across reboot or across devices.
-     * <p>This method will always return a valid timestamp on
-     * Locations generated by a {@link LocationProvider}.
+     *
+     * <p>All locations generated by the {@link LocationManager}
+     * are guaranteed to have a valid UTC time, however remember that
+     * the system time may have changed since the location was generated.
      *
      * @return time of fix, in milliseconds since January 1, 1970.
      */
@@ -491,13 +503,16 @@
 
     /**
      * Return the time of this fix, in elapsed real-time since system boot.
+     *
      * <p>This value can be reliably compared to
-     * {@link android.os.SystemClock#elapsedRealtimeNano()},
-     * to calculate the age of a fix, and to compare Location fixes, since
-     * elapsed real-time is guaranteed monotonic for each system boot, and
-     * continues to increment even when the system is in deep sleep.
-     * <p>This method will always return a valid timestamp on
-     * Locations generated by a {@link LocationProvider}.
+     * {@link android.os.SystemClock#elapsedRealtimeNano},
+     * to calculate the age of a fix and to compare Location fixes. This
+     * is reliable because elapsed real-time is guaranteed monotonic for
+     * each system boot and continues to increment even when the system
+     * is in deep sleep (unlike {@link #getTime}.
+     *
+     * <p>All locations generated by the {@link LocationManager}
+     * are guaranteed to have a valid elapsed real-time.
      *
      * @return elapsed real-time of fix, in nanoseconds since system boot.
      */
@@ -515,56 +530,59 @@
     }
 
     /**
-     * Return the latitude of this fix.
-     * <p>This method will always return a valid latitude on
-     * Locations generated by a {@link LocationProvider}.
+     * Get the latitude, in degrees.
+     *
+     * <p>All locations generated by the {@link LocationManager}
+     * will have a valid latitude.
      */
     public double getLatitude() {
         return mLatitude;
     }
 
     /**
-     * Sets the latitude of this fix.
+     * Set the latitude, in degrees.
      */
     public void setLatitude(double latitude) {
         mLatitude = latitude;
     }
 
     /**
-     * Return the longitude of this fix.
-     * <p>This method will always return a valid longitude on
-     * Locations generated by a {@link LocationProvider}.
+     * Get the longitude, in degrees.
+     *
+     * <p>All locations generated by the {@link LocationManager}
+     * will have a valid longitude.
      */
     public double getLongitude() {
         return mLongitude;
     }
 
     /**
-     * Sets the longitude of this fix.
+     * Set the longitude, in degrees.
      */
     public void setLongitude(double longitude) {
         mLongitude = longitude;
     }
 
     /**
-     * Returns true if this fix contains altitude information, false
-     * otherwise.
+     * True if this location has an altitude.
      */
     public boolean hasAltitude() {
         return mHasAltitude;
     }
 
     /**
-     * Returns the altitude of this fix.  If {@link #hasAltitude} is false,
-     * 0.0f is returned.
+     * Get the altitude if available, in meters above sea level.
+     *
+     * <p>If this location does not have an altitude then 0.0 is returned.
      */
     public double getAltitude() {
         return mAltitude;
     }
 
     /**
-     * Sets the altitude of this fix.  Following this call,
-     * hasAltitude() will return true.
+     * Set the altitude, in meters above sea level.
+     *
+     * <p>Following this call {@link #hasAltitude} will return true.
      */
     public void setAltitude(double altitude) {
         mAltitude = altitude;
@@ -572,8 +590,10 @@
     }
 
     /**
-     * Clears the altitude of this fix.  Following this call,
-     * hasAltitude() will return false.
+     * Remove the altitude from this location.
+     *
+     * <p>Following this call {@link #hasAltitude} will return false,
+     * and {@link #getAltitude} will return 0.0.
      */
     public void removeAltitude() {
         mAltitude = 0.0f;
@@ -581,24 +601,25 @@
     }
 
     /**
-     * Returns true if this fix contains speed information, false
-     * otherwise.  The default implementation returns false.
+     * True if this location has a speed.
      */
     public boolean hasSpeed() {
         return mHasSpeed;
     }
 
     /**
-     * Returns the speed of the device over ground in meters/second.
-     * If hasSpeed() is false, 0.0f is returned.
+     * Get the speed if it is available, in meters/second over ground.
+     *
+     * <p>If this location does not have a speed then 0.0 is returned.
      */
     public float getSpeed() {
         return mSpeed;
     }
 
     /**
-     * Sets the speed of this fix, in meters/second.  Following this
-     * call, hasSpeed() will return true.
+     * Set the speed, in meters/second over ground.
+     *
+     * <p>Following this call {@link #hasSpeed} will return true.
      */
     public void setSpeed(float speed) {
         mSpeed = speed;
@@ -606,8 +627,10 @@
     }
 
     /**
-     * Clears the speed of this fix.  Following this call, hasSpeed()
-     * will return false.
+     * Remove the speed from this location.
+     *
+     * <p>Following this call {@link #hasSpeed} will return false,
+     * and {@link #getSpeed} will return 0.0.
      */
     public void removeSpeed() {
         mSpeed = 0.0f;
@@ -615,24 +638,32 @@
     }
 
     /**
-     * Returns true if the provider is able to report bearing information,
-     * false otherwise.  The default implementation returns false.
+     * True if this location has a bearing.
      */
     public boolean hasBearing() {
         return mHasBearing;
     }
 
     /**
-     * Returns the direction of travel in degrees East of true
-     * North. If hasBearing() is false, 0.0 is returned.
+     * Get the bearing, in degrees.
+     *
+     * <p>Bearing is the horizontal direction of travel of this device,
+     * and is not related to the device orientation. It is guaranteed to
+     * be in the range (0.0, 360.0] if the device has a bearing.
+     *
+     * <p>If this location does not have a bearing then 0.0 is returned.
      */
     public float getBearing() {
         return mBearing;
     }
 
     /**
-     * Sets the bearing of this fix.  Following this call, hasBearing()
-     * will return true.
+     * Set the bearing, in degrees.
+     *
+     * <p>Bearing is the horizontal direction of travel of this device,
+     * and is not related to the device orientation.
+     *
+     * <p>The input will be wrapped into the range (0.0, 360.0].
      */
     public void setBearing(float bearing) {
         while (bearing < 0.0f) {
@@ -646,8 +677,10 @@
     }
 
     /**
-     * Clears the bearing of this fix.  Following this call, hasBearing()
-     * will return false.
+     * Remove the bearing from this location.
+     *
+     * <p>Following this call {@link #hasBearing} will return false,
+     * and {@link #getBearing} will return 0.0.
      */
     public void removeBearing() {
         mBearing = 0.0f;
@@ -655,35 +688,47 @@
     }
 
     /**
-     * Return true if this Location has an associated accuracy.
-     * <p>All Location objects generated by a {@link LocationProvider}
-     * will have an accuracy.
+     * True if this location has an accuracy.
+     *
+     * <p>All locations generated by the {@link LocationManager} have an
+     * accuracy.
      */
     public boolean hasAccuracy() {
         return mHasAccuracy;
     }
 
     /**
-     * Return the accuracy of this Location fix.
-     * <p>Accuracy is measured in meters, and indicates the
-     * radius of 95% confidence.
-     * In other words, there is a 95% probability that the
-     * true location is within a circle centered at the reported
-     * location, with radius of the reported accuracy.
-     * <p>This is only a measure of horizontal accuracy, and does
-     * not indicate the accuracy of bearing, velocity or altitude
-     * if those are included in this Location.
-     * <p>If {@link #hasAccuracy} is false, 0.0 is returned.
-     * <p>All Location object generated by a {@link LocationProvider}
-     * will have a valid accuracy.
+     * Get the estimated accuracy of this location, in meters.
+     *
+     * <p>We define accuracy as the radius of 68% confidence. In other
+     * words, if you draw a circle centered at this location's
+     * latitude and longitude, and with a radius equal to the accuracy,
+     * then there is a 68% probability that the true location is inside
+     * the circle.
+     *
+     * <p>In statistical terms, it is assumed that location errors
+     * are random with a normal distribution, so the 68% confidence circle
+     * represents one standard deviation. Note that in practice, location
+     * errors do not always follow such a simple distribution.
+     *
+     * <p>This accuracy estimation is only concerned with horizontal
+     * accuracy, and does not indicate the accuracy of bearing,
+     * velocity or altitude if those are included in this Location.
+     *
+     * <p>If this location does not have an accuracy, then 0.0 is returned.
+     * All locations generated by the {@link LocationManager} include
+     * an accuracy.
      */
     public float getAccuracy() {
         return mAccuracy;
     }
 
     /**
-     * Sets the accuracy of this fix.  Following this call, hasAccuracy()
-     * will return true.
+     * Set the estimated accuracy of this location, meters.
+     *
+     * <p>See {@link #getAccuracy} for the definition of accuracy.
+     *
+     * <p>Following this call {@link #hasAccuracy} will return true.
      */
     public void setAccuracy(float accuracy) {
         mAccuracy = accuracy;
@@ -691,8 +736,10 @@
     }
 
     /**
-     * Clears the accuracy of this fix.  Following this call, hasAccuracy()
-     * will return false.
+     * Remove the accuracy from this location.
+     *
+     * <p>Following this call {@link #hasAccuracy} will return false, and
+     * {@link #getAccuracy} will return 0.0.
      */
     public void removeAccuracy() {
         mAccuracy = 0.0f;
@@ -700,8 +747,14 @@
     }
 
     /**
-     * Return true if this Location object has enough data set to
-     * be considered a valid fix from a {@link LocationProvider}.
+     * Return true if this Location object is complete.
+     *
+     * <p>A location object is currently considered complete if it has
+     * a valid provider, accuracy, wall-clock time and elapsed real-time.
+     *
+     * <p>All locations supplied by the {@link LocationManager} to
+     * applications must be complete.
+     *
      * @see #makeComplete
      * @hide
      */
@@ -714,9 +767,11 @@
     }
 
     /**
-     * Helper to fill in incomplete fields.
-     * Only use this to assist in backwards compatibility
-     * with Location objects received from applications.
+     * Helper to fill incomplete fields.
+     *
+     * <p>Used to assist in backwards compatibility with
+     * Location objects received from applications.
+     *
      * @see #isComplete
      * @hide
      */
@@ -770,9 +825,8 @@
         if (mElapsedRealtimeNano == 0) {
             s.append(" et=?!?");
         } else {
-            long age = SystemClock.elapsedRealtimeNano() - mElapsedRealtimeNano;
-            s.append(" age=");
-            TimeUtils.formatDuration(age / 1000000L, s);
+            s.append(" et=");
+            TimeUtils.formatDuration(mElapsedRealtimeNano / 1000000L, s);
         }
         if (mHasAltitude) s.append(" alt=").append(mAltitude);
         if (mHasSpeed) s.append(" vel=").append(mSpeed);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 5f87c84..bef363b 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -46,12 +46,41 @@
  * {@link android.content.Context#getSystemService
  * Context.getSystemService(Context.LOCATION_SERVICE)}.
  *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about using location services, read the
- * <a href="{@docRoot}guide/topics/location/index.html">Location and Maps</a>
- * developer guide.</p>
- * </div>
+ * <p>At API version 17 the Location API's were simplified.
+ * Previously applications would need to explicitly enumerate, select, and
+ * track Location Providers (such as GPS or Network).
+ * This has been replaced by the concept of
+ * <em>Fused Location</em>. Now applications just specify the quality of service
+ * required for location updates (using the new {@link LocationRequest} class),
+ * and the system will fuse results from individual location providers
+ * as necessary before returning the result to the application.
+ *
+ * <p>As a result of this change, the {@link LocationProvider} and
+ * {@link Criteria} classes have been deprecated, in favor of
+ * {@link LocationRequest}. Furthermore, all Location Manager
+ * methods involving Criteria or explicitly named Providers have
+ * been deprecated, in favor of new variants that use
+ * {@link LocationRequest}.
+ *
+ * <p>A single {@link LocationRequest} object can trigger the use
+ * of all providers (including GPS, Network, and the passive) provider
+ * as necessary. This should result in a lot less work for your application. You
+ * no longer need to track the status and availability of each
+ * location provider. Just set the quality of locations required
+ * in {@link LocationRequest}, and let the system manage the rest.
+ *
+ * <p class="note">Unless noted, all Location API methods require
+ * the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} or
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permissions.
+ * If your application only has the Coarse permission then it will still
+ * receive location results, but the update rate will be throttled and
+ * the exact location will be obfuscated to a coarse level of accuracy.
+ *
+ * <p> class="note">Before API level 17, the use of 'fine' location
+ * providers such as GPS required the fine permission. As of API level
+ * 17, applications with only the coarse permission may use all providers,
+ * including GPS, but the locations are obfuscated (made coarse) before
+ * being sent to the application.
  */
 public class LocationManager {
     private static final String TAG = "LocationManager";
@@ -65,56 +94,69 @@
     private final GpsStatus mGpsStatus = new GpsStatus();
 
     /**
-     * Name of the network location provider.  This provider determines location based on
+     * Name of the network location provider.
+     * <p>This provider determines location based on
      * availability of cell tower and WiFi access points. Results are retrieved
      * by means of a network lookup.
      *
-     * Requires either of the permissions android.permission.ACCESS_COARSE_LOCATION
-     * or android.permission.ACCESS_FINE_LOCATION.
-     * @deprecated use the {@link Criteria} class instead
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public static final String NETWORK_PROVIDER = "network";
 
     /**
-     * Name of the GPS location provider. This provider determines location using
+     * Name of the GPS location provider.
+     *
+     * <p>This provider determines location using
      * satellites. Depending on conditions, this provider may take a while to return
      * a location fix.
      *
-     * Requires the permission android.permission.ACCESS_FINE_LOCATION.
+     * <p>Before API version 17, this provider required the
+     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
+     * From API version 17 and onwards, this provider can also be used with
+     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}, however
+     * the locations returned will be obfuscated to a coarse level of accuracy.
      *
      * <p> The extras Bundle for the GPS location provider can contain the
      * following key/value pairs:
-     *
      * <ul>
      * <li> satellites - the number of satellites used to derive the fix
      * </ul>
-     * @deprecated use the {@link Criteria} class instead
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public static final String GPS_PROVIDER = "gps";
 
     /**
      * A special location provider for receiving locations without actually initiating
-     * a location fix. This provider can be used to passively receive location updates
+     * a location fix.
+     *
+     * <p>This provider can be used to passively receive location updates
      * when other applications or services request them without actually requesting
      * the locations yourself.  This provider will return locations generated by other
      * providers.  You can query the {@link Location#getProvider()} method to determine
      * the origin of the location update.
      *
-     * Requires the permission android.permission.ACCESS_FINE_LOCATION, although if the GPS
-     * is not enabled this provider might only return coarse fixes.
-     * @deprecated use the {@link Criteria} class instead
+     * <p>Before API version 17, this provider required the
+     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
+     * From API version 17 and onwards, this provider can also be used with
+     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}, however
+     * the locations returned will be obfuscated to a coarse level of accuracy.
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public static final String PASSIVE_PROVIDER = "passive";
 
     /**
-     * Name of the Fused location provider.<p>
-     * This provider combines inputs for all possible location sources
-     * to provide the best possible Location fix.<p>
+     * Name of the Fused location provider.
      *
-     * Requires the permission android.permission.ACCESS_FINE_LOCATION.
+     * <p>This provider combines inputs for all possible location sources
+     * to provide the best possible Location fix. It is implicitly
+     * used for all API's that involve the {@link LocationRequest}
+     * object.
+     *
      * @hide
      */
     public static final String FUSED_PROVIDER = "fused";
@@ -128,7 +170,8 @@
     /**
      * Key used for a Bundle extra holding an Integer status value
      * when a status change is broadcast using a PendingIntent.
-     * @deprecated use the {@link Criteria} class instead
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public static final String KEY_STATUS_CHANGED = "status";
@@ -136,7 +179,8 @@
     /**
      * Key used for a Bundle extra holding an Boolean status value
      * when a provider enabled/disabled event is broadcast using a PendingIntent.
-     * @deprecated use the {@link Criteria} class instead
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -153,7 +197,7 @@
      * where {@code true} means enabled.
      * @see #EXTRA_GPS_ENABLED
      *
-     * {@hide}
+     * @hide
      */
     public static final String GPS_ENABLED_CHANGE_ACTION =
         "android.location.GPS_ENABLED_CHANGE";
@@ -161,7 +205,8 @@
     /**
      * Broadcast intent action when the configured location providers
      * change.
-     * @deprecated use the {@link Criteria} class instead
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public static final String PROVIDERS_CHANGED_ACTION =
@@ -173,7 +218,7 @@
      * boolean, where {@code true} means that the GPS is actively receiving fixes.
      * @see #EXTRA_GPS_ENABLED
      *
-     * {@hide}
+     * @hide
      */
     public static final String GPS_FIX_CHANGE_ACTION =
         "android.location.GPS_FIX_CHANGE";
@@ -183,7 +228,7 @@
      * disabled. {@code true} means GPS is enabled. Retrieve it with
      * {@link android.content.Intent#getBooleanExtra(String,boolean)}.
      *
-     * {@hide}
+     * @hide
      */
     public static final String EXTRA_GPS_ENABLED = "enabled";
 
@@ -285,6 +330,7 @@
             }
         }
     }
+
     /**
      * @hide - hide this constructor because it has a parameter
      * of type ILocationManager, which is a system private class. The
@@ -301,12 +347,13 @@
     }
 
     /**
-     * Returns a list of the names of all known location providers.  All
-     * providers are returned, including ones that are not permitted to be
-     * accessed by the calling activity or are currently disabled.
+     * Returns a list of the names of all known location providers.
+     * <p>All providers are returned, including ones that are not permitted to
+     * be accessed by the calling activity or are currently disabled.
      *
-     * @return list of Strings containing names of the providers
-     * @deprecated use the {@link Criteria} class instead
+     * @return list of Strings containing names of the provider
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public List<String> getAllProviders() {
@@ -319,15 +366,13 @@
     }
 
     /**
-     * Returns a list of the names of location providers.  Only providers that
-     * are permitted to be accessed by the calling activity will be returned.
+     * Returns a list of the names of location providers.
      *
      * @param enabledOnly if true then only the providers which are currently
      * enabled are returned.
      * @return list of Strings containing names of the providers
-     * @deprecated The {@link LocationProvider} class is deprecated. So
-     * use the {@link Criteria} class to request location instead of
-     * enumerating providers.
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public List<String> getProviders(boolean enabledOnly) {
@@ -346,12 +391,11 @@
      * @param name the provider name
      * @return a LocationProvider, or null
      *
-     * @throws IllegalArgumentException if name is null or does not exisit
+     * @throws IllegalArgumentException if name is null or does not exist
      * @throws SecurityException if the caller is not permitted to access the
      * given provider.
-     * @deprecated The {@link LocationProvider} class is deprecated. So
-     * use the {@link Criteria} class to request location instead of
-     * enumerating providers.
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public LocationProvider getProvider(String name) {
@@ -377,9 +421,8 @@
      * @param enabledOnly if true then only the providers which are currently
      * enabled are returned.
      * @return list of Strings containing names of the providers
-     * @deprecated The {@link LocationProvider} class is deprecated. So
-     * use the {@link Criteria} class to request location instead of
-     * enumerating providers.
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
@@ -413,7 +456,8 @@
      * @param criteria the criteria that need to be matched
      * @param enabledOnly if true then only a provider that is currently enabled is returned
      * @return name of the provider that best matches the requirements
-     * @deprecated using an explicit provider doesn't allow fused location
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public String getBestProvider(Criteria criteria, boolean enabledOnly) {
@@ -427,64 +471,11 @@
     }
 
     /**
-     * Registers the current activity to be notified periodically by
-     * the named provider.  Periodically, the supplied LocationListener will
-     * be called with the current Location or with status updates.
+     * Register for location updates using the named provider, and a
+     * pending intent.
      *
-     * <p> It may take a while to receive the first location update. If
-     * an immediate location is required, applications may use the
-     * {@link #getLastKnownLocation(String)} method.
-     *
-     * <p> In case the provider is disabled by the user, updates will stop,
-     * and the {@link LocationListener#onProviderDisabled(String)}
-     * method will be called. As soon as the provider is enabled again,
-     * the {@link LocationListener#onProviderEnabled(String)} method will
-     * be called and location updates will start again.
-     *
-     * <p> The update interval can be controlled using the minTime parameter.
-     * The elapsed time between location updates will never be less than
-     * minTime, although it can be more depending on the Location Provider
-     * implementation and the update interval requested by other applications.
-     *
-     * <p> Choosing a sensible value for minTime is important to conserve
-     * battery life. Each location update requires power from
-     * GPS, WIFI, Cell and other radios. Select a minTime value as high as
-     * possible while still providing a reasonable user experience.
-     * If your application is not in the foreground and showing
-     * location to the user then your application should avoid using an active
-     * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}),
-     * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes)
-     * or greater. If your application is in the foreground and showing
-     * location to the user then it is appropriate to select a faster
-     * update interval.
-     *
-     * <p> The minDistance parameter can also be used to control the
-     * frequency of location updates. If it is greater than 0 then the
-     * location provider will only send your application an update when
-     * the location has changed by at least minDistance meters, AND
-     * at least minTime milliseconds have passed. However it is more
-     * difficult for location providers to save power using the minDistance
-     * parameter, so minTime should be the primary tool to conserving battery
-     * life.
-     *
-     * <p> If your application wants to passively observe location
-     * updates triggered by other applications, but not consume
-     * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER}
-     * This provider does not actively turn on or modify active location
-     * providers, so you do not need to be as careful about minTime and
-     * minDistance. However if your application performs heavy work
-     * on a location update (such as network activity) then you should
-     * select non-zero values for minTime and/or minDistance to rate-limit
-     * your update frequency in the case another application enables a
-     * location provider with extremely fast updates.
-     *
-     * <p> The calling thread must be a {@link android.os.Looper} thread such as
-     * the main thread of the calling Activity.
-     *
-     * <p class="note"> Prior to Jellybean, the minTime parameter was
-     * only a hint, and some location provider implementations ignored it.
-     * From Jellybean and onwards it is mandatory for Android compatible
-     * devices to observe both the minTime and minDistance parameters.
+     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
+     * for more detail on how to use this (deprecated) method.
      *
      * @param provider the name of the provider with which to register
      * @param minTime minimum time interval between location updates, in milliseconds
@@ -497,8 +488,8 @@
      * on this device
      * @throws IllegalArgumentException if listener is null
      * @throws RuntimeException if the calling thread has no Looper
-     * @throws SecurityException if no suitable permission is present for the provider.
-     * @deprecated use the {@link LocationRequest} class instead
+     * @throws SecurityException if no suitable permission is present
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public void requestLocationUpdates(String provider, long minTime, float minDistance,
@@ -512,63 +503,11 @@
     }
 
     /**
-     * Registers the current activity to be notified periodically by
-     * the named provider.  Periodically, the supplied LocationListener will
-     * be called with the current Location or with status updates.
+     * Register for location updates using the named provider, and a callback on
+     * the specified looper thread.
      *
-     * <p> It may take a while to receive the first location update. If
-     * an immediate location is required, applications may use the
-     * {@link #getLastKnownLocation(String)} method.
-     *
-     * <p> In case the provider is disabled by the user, updates will stop,
-     * and the {@link LocationListener#onProviderDisabled(String)}
-     * method will be called. As soon as the provider is enabled again,
-     * the {@link LocationListener#onProviderEnabled(String)} method will
-     * be called and location updates will start again.
-     *
-     * <p> The update interval can be controlled using the minTime parameter.
-     * The elapsed time between location updates will never be less than
-     * minTime, although it can be more depending on the Location Provider
-     * implementation and the update interval requested by other applications.
-     *
-     * <p> Choosing a sensible value for minTime is important to conserve
-     * battery life. Each location update requires power from
-     * GPS, WIFI, Cell and other radios. Select a minTime value as high as
-     * possible while still providing a reasonable user experience.
-     * If your application is not in the foreground and showing
-     * location to the user then your application should avoid using an active
-     * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}),
-     * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes)
-     * or greater. If your application is in the foreground and showing
-     * location to the user then it is appropriate to select a faster
-     * update interval.
-     *
-     * <p> The minDistance parameter can also be used to control the
-     * frequency of location updates. If it is greater than 0 then the
-     * location provider will only send your application an update when
-     * the location has changed by at least minDistance meters, AND
-     * at least minTime milliseconds have passed. However it is more
-     * difficult for location providers to save power using the minDistance
-     * parameter, so minTime should be the primary tool to conserving battery
-     * life.
-     *
-     * <p> If your application wants to passively observe location
-     * updates triggered by other applications, but not consume
-     * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER}
-     * This provider does not actively turn on or modify active location
-     * providers, so you do not need to be as careful about minTime and
-     * minDistance. However if your application performs heavy work
-     * on a location update (such as network activity) then you should
-     * select non-zero values for minTime and/or minDistance to rate-limit
-     * your update frequency in the case another application enables a
-     * location provider with extremely fast updates.
-     *
-     * <p> The supplied Looper is used to implement the callback mechanism.
-     *
-     * <p class="note"> Prior to Jellybean, the minTime parameter was
-     * only a hint, and some location provider implementations ignored it.
-     * From Jellybean and onwards it is mandatory for Android compatible
-     * devices to observe both the minTime and minDistance parameters.
+     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
+     * for more detail on how to use this (deprecated) method.
      *
      * @param provider the name of the provider with which to register
      * @param minTime minimum time interval between location updates, in milliseconds
@@ -577,13 +516,14 @@
      * {@link LocationListener#onLocationChanged} method will be called for
      * each location update
      * @param looper a Looper object whose message queue will be used to
-     * implement the callback mechanism, or null to make callbacks on the
-     * main thread
+     * implement the callback mechanism, or null to make callbacks on the calling
+     * thread
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if listener is null
-     * @throws SecurityException if no suitable permission is present for the provider.
-     * @deprecated use the {@link LocationRequest} class instead
+     * @throws SecurityException if no suitable permission is present
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public void requestLocationUpdates(String provider, long minTime, float minDistance,
@@ -597,52 +537,11 @@
     }
 
     /**
-     * Registers the current activity to be notified periodically based on
-     * the supplied criteria.  Periodically, the supplied LocationListener will
-     * be called with the current Location or with status updates.
+     * Register for location updates using a Criteria, and a callback
+     * on the specified looper thread.
      *
-     * <p> It may take a while to receive the first location update. If
-     * an immediate location is required, applications may use the
-     * {@link #getLastKnownLocation(String)} method.
-     *
-     * <p> In case the provider is disabled by the user, updates will stop,
-     * and the {@link LocationListener#onProviderDisabled(String)}
-     * method will be called. As soon as the provider is enabled again,
-     * the {@link LocationListener#onProviderEnabled(String)} method will
-     * be called and location updates will start again.
-     *
-     * <p> The update interval can be controlled using the minTime parameter.
-     * The elapsed time between location updates will never be less than
-     * minTime, although it can be more depending on the Location Provider
-     * implementation and the update interval requested by other applications.
-     *
-     * <p> Choosing a sensible value for minTime is important to conserve
-     * battery life. Each location update requires power from
-     * GPS, WIFI, Cell and other radios. Select a minTime value as high as
-     * possible while still providing a reasonable user experience.
-     * If your application is not in the foreground and showing
-     * location to the user then your application should avoid using an active
-     * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}),
-     * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes)
-     * or greater. If your application is in the foreground and showing
-     * location to the user then it is appropriate to select a faster
-     * update interval.
-     *
-     * <p> The minDistance parameter can also be used to control the
-     * frequency of location updates. If it is greater than 0 then the
-     * location provider will only send your application an update when
-     * the location has changed by at least minDistance meters, AND
-     * at least minTime milliseconds have passed. However it is more
-     * difficult for location providers to save power using the minDistance
-     * parameter, so minTime should be the primary tool to conserving battery
-     * life.
-     *
-     * <p> The supplied Looper is used to implement the callback mechanism.
-     *
-     * <p class="note"> Prior to Jellybean, the minTime parameter was
-     * only a hint, and some location provider implementations ignored it.
-     * From Jellybean and onwards it is mandatory for Android compatible
-     * devices to observe both the minTime and minDistance parameters.
+     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
+     * for more detail on how to use this (deprecated) method.
      *
      * @param minTime minimum time interval between location updates, in milliseconds
      * @param minDistance minimum distance between location updates, in meters
@@ -652,13 +551,14 @@
      * {@link LocationListener#onLocationChanged} method will be called for
      * each location update
      * @param looper a Looper object whose message queue will be used to
-     * implement the callback mechanism, or null to make callbacks on the
-     * main thread.
+     * implement the callback mechanism, or null to make callbacks on the calling
+     * thread
      *
      * @throws IllegalArgumentException if criteria is null
      * @throws IllegalArgumentException if listener is null
-     * @throws SecurityException if no suitable permission is present for the provider.
-     * @deprecated use the {@link LocationRequest} class instead
+     * @throws SecurityException if no suitable permission is present
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,
@@ -672,70 +572,11 @@
     }
 
     /**
-     * Registers the current activity to be notified periodically by
-     * the named provider.  Periodically, the supplied PendingIntent will
-     * be broadcast with the current Location or with status updates.
+     * Register for location updates using the named provider, and a
+     * pending intent.
      *
-     * <p> Location updates are sent with a key of
-     * {@link #KEY_LOCATION_CHANGED} and a {@link android.location.Location} value.
-     *
-     * <p> It may take a while to receive the first location update. If
-     * an immediate location is required, applications may use the
-     * {@link #getLastKnownLocation(String)} method.
-     *
-     * <p> The update interval can be controlled using the minTime parameter.
-     * The elapsed time between location updates will never be less than
-     * minTime, although it can be more depending on the Location Provider
-     * implementation and the update interval requested by other applications.
-     *
-     * <p> Choosing a sensible value for minTime is important to conserve
-     * battery life. Each location update requires power from
-     * GPS, WIFI, Cell and other radios. Select a minTime value as high as
-     * possible while still providing a reasonable user experience.
-     * If your application is not in the foreground and showing
-     * location to the user then your application should avoid using an active
-     * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}),
-     * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes)
-     * or greater. If your application is in the foreground and showing
-     * location to the user then it is appropriate to select a faster
-     * update interval.
-     *
-     * <p> The minDistance parameter can also be used to control the
-     * frequency of location updates. If it is greater than 0 then the
-     * location provider will only send your application an update when
-     * the location has changed by at least minDistance meters, AND
-     * at least minTime milliseconds have passed. However it is more
-     * difficult for location providers to save power using the minDistance
-     * parameter, so minTime should be the primary tool to conserving battery
-     * life.
-     *
-     * <p> If your application wants to passively observe location
-     * updates triggered by other applications, but not consume
-     * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER}
-     * This provider does not actively turn on or modify active location
-     * providers, so you do not need to be as careful about minTime and
-     * minDistance. However if your application performs heavy work
-     * on a location update (such as network activity) then you should
-     * select non-zero values for minTime and/or minDistance to rate-limit
-     * your update frequency in the case another application enables a
-     * location provider with extremely fast updates.
-     *
-     * <p> If the provider is disabled by the user, updates will stop,
-     * and an intent will be sent with an extra with key
-     * {@link #KEY_PROVIDER_ENABLED} and a boolean value of false.
-     * If the provider is re-enabled, an intent will be sent with an
-     * extra with key {@link #KEY_PROVIDER_ENABLED} and a boolean value of
-     * true and location updates will start again.
-     *
-     * <p> If the provider's status changes, an intent will be sent with
-     * an extra with key {@link #KEY_STATUS_CHANGED} and an integer value
-     * indicating the new status.  Any extras associated with the status
-     * update will be sent as well.
-     *
-     * <p class="note"> Prior to Jellybean, the minTime parameter was
-     * only a hint, and some location provider implementations ignored it.
-     * From Jellybean and onwards it is mandatory for Android compatible
-     * devices to observe both the minTime and minDistance parameters.
+     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
+     * for more detail on how to use this (deprecated) method.
      *
      * @param provider the name of the provider with which to register
      * @param minTime minimum time interval between location updates, in milliseconds
@@ -745,8 +586,9 @@
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * on this device
      * @throws IllegalArgumentException if intent is null
-     * @throws SecurityException if no suitable permission is present for the provider.
-     * @deprecated use the {@link LocationRequest} class instead
+     * @throws SecurityException if no suitable permission is present
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public void requestLocationUpdates(String provider, long minTime, float minDistance,
@@ -760,18 +602,28 @@
     }
 
     /**
-     * Registers the current activity to be notified periodically based on
-     * the supplied criteria.  Periodically, the supplied PendingIntent will
-     * be broadcast with the current Location or with status updates.
+     * Register for location updates using a Criteria and pending intent.
      *
-     * <p> Location updates are sent with a key of
-     * {@link #KEY_LOCATION_CHANGED} and a {@link android.location.Location} value.
+     * <p>The <code>requestLocationUpdates()</code> and
+     * <code>requestSingleUpdate()</code> methods involving
+     * an explicit String provider or {@link Criteria} are deprecated.
+     *
+     * <p>They register the current activity to be updated
+     * periodically by the named provider, or by the provider matching
+     * the specified {@link Criteria}, with location and status updates.
      *
      * <p> It may take a while to receive the first location update. If
      * an immediate location is required, applications may use the
      * {@link #getLastKnownLocation(String)} method.
      *
-     * <p> The update interval can be controlled using the minTime parameter.
+     * <p> Location updates are received either by {@link LocationListener}
+     * callbacks, or by broadcast intents to a supplied {@link PendingIntent}.
+     *
+     * <p> If the caller supplied a pending intent, then location updates
+     * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a
+     * {@link android.location.Location} value.
+     *
+     * <p> The location update interval can be controlled using the minTime parameter.
      * The elapsed time between location updates will never be less than
      * minTime, although it can be more depending on the Location Provider
      * implementation and the update interval requested by other applications.
@@ -797,17 +649,36 @@
      * parameter, so minTime should be the primary tool to conserving battery
      * life.
      *
-     * <p> If the provider is disabled by the user, updates will stop,
-     * and an intent will be sent with an extra with key
-     * {@link #KEY_PROVIDER_ENABLED} and a boolean value of false.
-     * If the provider is re-enabled, an intent will be sent with an
-     * extra with key {@link #KEY_PROVIDER_ENABLED} and a boolean value of
-     * true and location updates will start again.
+     * <p> If your application wants to passively observe location
+     * updates triggered by other applications, but not consume
+     * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER}
+     * This provider does not actively turn on or modify active location
+     * providers, so you do not need to be as careful about minTime and
+     * minDistance. However if your application performs heavy work
+     * on a location update (such as network activity) then you should
+     * select non-zero values for minTime and/or minDistance to rate-limit
+     * your update frequency in the case another application enables a
+     * location provider with extremely fast updates.
      *
-     * <p> If the provider's status changes, an intent will be sent with
-     * an extra with key {@link #KEY_STATUS_CHANGED} and an integer value
-     * indicating the new status.  Any extras associated with the status
-     * update will be sent as well.
+     * <p>In case the provider is disabled by the user, updates will stop,
+     * and a provider availability update will be sent.
+     * As soon as the provider is enabled again,
+     * location updates will immediately resume and a provider availability
+     * update sent. Providers can also send status updates, at any time,
+     * with extra's specific to the provider. If a callback was supplied
+     * then status and availability updates are via
+     * {@link LocationListener#onProviderDisabled},
+     * {@link LocationListener#onProviderEnabled} or
+     * {@link LocationListener#onStatusChanged}. Alternately, if a
+     * pending intent was supplied then status and availability updates
+     * are broadcast intents with extra keys of
+     * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED}.
+     *
+     * <p> If a {@link LocationListener} is used but with no Looper specified
+     * then the calling thread must already
+     * be a {@link android.os.Looper} thread such as the main thread of the
+     * calling Activity. If a Looper is specified with a {@link LocationListener}
+     * then callbacks are made on the supplied Looper thread.
      *
      * <p class="note"> Prior to Jellybean, the minTime parameter was
      * only a hint, and some location provider implementations ignored it.
@@ -822,8 +693,9 @@
      *
      * @throws IllegalArgumentException if criteria is null
      * @throws IllegalArgumentException if intent is null
-     * @throws SecurityException if no suitable permission is present for the provider.
-     * @deprecated use the {@link LocationRequest} class instead
+     * @throws SecurityException if no suitable permission is present
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,
@@ -837,32 +709,25 @@
     }
 
     /**
-     * Requests a single location update from the named provider.
+     * Register for a single location update using the named provider and
+     * a callback.
      *
-     * <p> It may take a while to receive the most recent location. If
-     * an immediate location is required, applications may use the
-     * {@link #getLastKnownLocation(String)} method.
-     *
-     * <p> In case the provider is disabled by the user, the update will not be received,
-     * and the {@link LocationListener#onProviderDisabled(String)}
-     * method will be called. As soon as the provider is enabled again,
-     * the {@link LocationListener#onProviderEnabled(String)} method will
-     * be called and location updates will start again.
-     *
-     * <p> The supplied Looper is used to implement the callback mechanism.
+     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
+     * for more detail on how to use this (deprecated) method.
      *
      * @param provider the name of the provider with which to register
      * @param listener a {#link LocationListener} whose
      * {@link LocationListener#onLocationChanged} method will be called when
      * the location update is available
      * @param looper a Looper object whose message queue will be used to
-     * implement the callback mechanism, or null to make callbacks on the
-     * main thread
+     * implement the callback mechanism, or null to make callbacks on the calling
+     * thread
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if listener is null
-     * @throws SecurityException if no suitable permission is present for the provider
-     * @deprecated use the {@link LocationRequest} class instead
+     * @throws SecurityException if no suitable permission is present
+     *
+     * @deprecated Use {@link LocationRequest#setNumUpdates} instead
      */
     @Deprecated
     public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) {
@@ -875,19 +740,11 @@
     }
 
     /**
-     * Requests a single location update based on the specified criteria.
+     * Register for a single location update using a Criteria and
+     * a callback.
      *
-     * <p> It may take a while to receive the most recent location. If
-     * an immediate location is required, applications may use the
-     * {@link #getLastKnownLocation(String)} method.
-     *
-     * <p> In case the provider is disabled by the user, the update will not be received,
-     * and the {@link LocationListener#onProviderDisabled(String)}
-     * method will be called. As soon as the provider is enabled again,
-     * the {@link LocationListener#onProviderEnabled(String)} method will
-     * be called and location updates will start again.
-     *
-     * <p> The supplied Looper is used to implement the callback mechanism.
+     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
+     * for more detail on how to use this (deprecated) method.
      *
      * @param criteria contains parameters for the location manager to choose the
      * appropriate provider and parameters to compute the location
@@ -895,14 +752,14 @@
      * {@link LocationListener#onLocationChanged} method will be called when
      * the location update is available
      * @param looper a Looper object whose message queue will be used to
-     * implement the callback mechanism, or null to make callbacks on the
-     * main thread
+     * implement the callback mechanism, or null to make callbacks on the calling
+     * thread
      *
      * @throws IllegalArgumentException if criteria is null
      * @throws IllegalArgumentException if listener is null
-     * @throws SecurityException if no suitable permission is present to access
-     * the location services
-     * @deprecated use the {@link LocationRequest} class instead
+     * @throws SecurityException if no suitable permission is present
+     *
+     * @deprecated Use {@link LocationRequest#setNumUpdates} instead
      */
     @Deprecated
     public void requestSingleUpdate(Criteria criteria, LocationListener listener, Looper looper) {
@@ -915,28 +772,19 @@
     }
 
     /**
-     * Requests a single location update from the named provider.
+     * Register for a single location update using a named provider and pending intent.
      *
-     * <p> It may take a while to receive the most recent location. If
-     * an immediate location is required, applications may use the
-     * {@link #getLastKnownLocation(String)} method.
-     *
-     * <p> Location updates are sent with a key of
-     * {@link #KEY_LOCATION_CHANGED} and a {@link android.location.Location} value.
-     *
-     * <p> In case the provider is disabled by the user, the update will not be received,
-     * and the {@link LocationListener#onProviderDisabled(String)}
-     * method will be called. As soon as the provider is enabled again,
-     * the {@link LocationListener#onProviderEnabled(String)} method will
-     * be called and location updates will start again.
+     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
+     * for more detail on how to use this (deprecated) method.
      *
      * @param provider the name of the provider with which to register
      * @param intent a {#link PendingIntent} to be sent for the location update
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if intent is null
-     * @throws SecurityException if no suitable permission is present for the provider
-     * @deprecated use the {@link LocationRequest} class instead
+     * @throws SecurityException if no suitable permission is present
+     *
+     * @deprecated Use {@link LocationRequest#setNumUpdates} instead
      */
     @Deprecated
     public void requestSingleUpdate(String provider, PendingIntent intent) {
@@ -949,21 +797,10 @@
     }
 
     /**
-     * Requests a single location update based on the specified criteria.
+     * Register for a single location update using a Criteria and pending intent.
      *
-     * <p> It may take a while to receive the most recent location. If
-     * an immediate location is required, applications may use the
-     * {@link #getLastKnownLocation(String)} method.
-     *
-     * <p> Location updates are sent with a key of
-     * {@link #KEY_LOCATION_CHANGED} and a {@link android.location.Location} value.
-     *
-     * <p> If the provider is disabled by the user, an update will not be
-     * received, and an intent will be sent with an extra with key
-     * {@link #KEY_PROVIDER_ENABLED} and a boolean value of false.
-     * If the provider is re-enabled, an intent will be sent with an
-     * extra with key {@link #KEY_PROVIDER_ENABLED} and a boolean value of
-     * true and the location update will occur.
+     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
+     * for more detail on how to use this (deprecated) method.
      *
      * @param criteria contains parameters for the location manager to choose the
      * appropriate provider and parameters to compute the location
@@ -971,8 +808,9 @@
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if intent is null
-     * @throws SecurityException if no suitable permission is present for the provider
-     * @deprecated use the {@link LocationRequest} class instead
+     * @throws SecurityException if no suitable permission is present
+     *
+     * @deprecated Use {@link LocationRequest#setNumUpdates} instead
      */
     @Deprecated
     public void requestSingleUpdate(Criteria criteria, PendingIntent intent) {
@@ -984,12 +822,74 @@
         requestLocationUpdates(request, null, null, intent);
     }
 
+    /**
+     * Register for fused location updates using a LocationRequest and callback.
+     *
+     * <p>The system will automatically select and enable the best providers
+     * to compute a location for your application. It may use only passive
+     * locations, or just a single location source, or it may fuse together
+     * multiple location sources in order to produce the best possible
+     * result, depending on the quality of service requested in the
+     * {@link LocationRequest}.
+     *
+     * <p>LocationRequest can be null, in which case the system will choose
+     * default, low power parameters for location updates. You will occasionally
+     * receive location updates as available, without a major power impact on the
+     * system. If your application just needs an occasional location update
+     * without any strict demands, then pass a null LocationRequest.
+     *
+     * <p>Only one LocationRequest can be registered for each unique callback
+     * or pending intent. So a subsequent request with the same callback or
+     * pending intent will over-write the previous LocationRequest.
+     *
+     * <p> If a pending intent is supplied then location updates
+     * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a
+     * {@link android.location.Location} value. If a callback is supplied
+     * then location updates are made using the
+     * {@link LocationListener#onLocationChanged} callback, on the specified
+     * Looper thread. If a {@link LocationListener} is used
+     * but with a null Looper then the calling thread must already
+     * be a {@link android.os.Looper} thread (such as the main thread) and
+     * callbacks will occur on this thread.
+     *
+     * <p> Provider status updates and availability updates are deprecated
+     * because the system is performing provider fusion on the applications
+     * behalf. So {@link LocationListener#onProviderDisabled},
+     * {@link LocationListener#onProviderEnabled}, {@link LocationListener#onStatusChanged}
+     * will not be called, and intents with extra keys of
+     * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED} will not
+     * be received.
+     *
+     * @param request quality of service required, null for default low power
+     * @param listener a {#link LocationListener} whose
+     * {@link LocationListener#onLocationChanged} method will be called when
+     * the location update is available
+     * @param looper a Looper object whose message queue will be used to
+     * implement the callback mechanism, or null to make callbacks on the calling
+     * thread
+     *
+     * @throws IllegalArgumentException if listener is null
+     * @throws SecurityException if no suitable permission is present
+     */
     public void requestLocationUpdates(LocationRequest request, LocationListener listener,
             Looper looper) {
         checkListener(listener);
         requestLocationUpdates(request, listener, looper, null);
     }
 
+
+    /**
+     * Register for fused location updates using a LocationRequest and a pending intent.
+     *
+     * <p> See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)}
+     * for more detail.
+     *
+     * @param request quality of service required, null for default low power
+     * @param intent a {#link PendingIntent} to be sent for the location update
+     *
+     * @throws IllegalArgumentException if intent is null
+     * @throws SecurityException if no suitable permission is present
+     */
     public void requestLocationUpdates(LocationRequest request, PendingIntent intent) {
         checkPendingIntent(intent);
         requestLocationUpdates(request, null, null, intent);
@@ -1023,11 +923,12 @@
     }
 
     /**
-     * Removes any current registration for location updates of the current activity
-     * with the given LocationListener.  Following this call, updates will no longer
+     * Removes all location updates for the specified LocationListener.
+     *
+     * <p>Following this call, updates will no longer
      * occur for this listener.
      *
-     * @param listener {#link LocationListener} object that no longer needs location updates
+     * @param listener listener object that no longer needs location updates
      * @throws IllegalArgumentException if listener is null
      */
     public void removeUpdates(LocationListener listener) {
@@ -1048,11 +949,11 @@
     }
 
     /**
-     * Removes any current registration for location updates of the current activity
-     * with the given PendingIntent.  Following this call, updates will no longer
-     * occur for this intent.
+     * Removes all location updates for the specified pending intent.
      *
-     * @param intent {#link PendingIntent} object that no longer needs location updates
+     * <p>Following this call, updates will no longer for this pending intent.
+     *
+     * @param intent pending intent object that no longer needs location updates
      * @throws IllegalArgumentException if intent is null
      */
     public void removeUpdates(PendingIntent intent) {
@@ -1067,8 +968,10 @@
     }
 
     /**
-     * Sets a proximity alert for the location given by the position
-     * (latitude, longitude) and the given radius.  When the device
+     * Set a proximity alert for the location given by the position
+     * (latitude, longitude) and the given radius.
+     *
+     * <p> When the device
      * detects that it has entered or exited the area surrounding the
      * location, the given PendingIntent will be used to create an Intent
      * to be fired.
@@ -1088,10 +991,6 @@
      * alert and no longer monitor it.  A value of -1 indicates that
      * there should be no expiration time.
      *
-     * <p> In case the screen goes to sleep, checks for proximity alerts
-     * happen only once every 4 minutes. This conserves battery life by
-     * ensuring that the device isn't perpetually awake.
-     *
      * <p> Internally, this method uses both {@link #NETWORK_PROVIDER}
      * and {@link #GPS_PROVIDER}.
      *
@@ -1106,9 +1005,9 @@
      * @param intent a PendingIntent that will be used to generate an Intent to
      * fire when entry to or exit from the alert region is detected
      *
-     * @throws SecurityException if no permission exists for the required
-     * providers.
-     * @deprecated use the {@link LocationRequest} class instead
+     * @throws SecurityException if no suitable permission is present
+     *
+     * @deprecated Use {@link LocationRequest} and {@link Geofence} instead
      */
     @Deprecated
     public void addProximityAlert(double latitude, double longitude, float radius, long expiration,
@@ -1125,7 +1024,40 @@
         }
     }
 
-    public void requestGeofence(LocationRequest request, Geofence fence, PendingIntent intent) {
+    /**
+     * Add a geofence with the specified LocationRequest quality of service.
+     *
+     * <p> When the device
+     * detects that it has entered or exited the area surrounding the
+     * location, the given PendingIntent will be used to create an Intent
+     * to be fired.
+     *
+     * <p> The fired Intent will have a boolean extra added with key
+     * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is
+     * entering the proximity region; if false, it is exiting.
+     *
+     * <p> The geofence engine fuses results from all location providers to
+     * provide the best balance between accuracy and power. Applications
+     * can choose the quality of service required using the
+     * {@link LocationRequest} object. If it is null then a default,
+     * low power geo-fencing implementation is used. It is possible to cross
+     * a geo-fence without notification, but the system will do its best
+     * to detect, using {@link LocationRequest} as a hint to trade-off
+     * accuracy and power.
+     *
+     * <p> The power required by the geofence engine can depend on many factors,
+     * such as quality and interval requested in {@link LocationRequest},
+     * distance to nearest geofence and current device velocity.
+     *
+     * @param request quality of service required, null for default low power
+     * @param fence a geographical description of the geofence area
+     * @param intent pending intent to receive geofence updates
+     *
+     * @throws IllegalArgumentException if fence is null
+     * @throws IllegalArgumentException if intent is null
+     * @throws SecurityException if no suitable permission is present
+     */
+    public void addGeofence(LocationRequest request, Geofence fence, PendingIntent intent) {
         checkPendingIntent(intent);
         checkGeofence(fence);
 
@@ -1141,7 +1073,11 @@
      *
      * @param intent the PendingIntent that no longer needs to be notified of
      * proximity alerts
-     * @deprecated use the {@link LocationRequest} class instead
+     *
+     * @throws IllegalArgumentException if intent is null
+     * @throws SecurityException if no suitable permission is present
+     *
+     * @deprecated Use {@link LocationRequest} and {@link Geofence} instead
      */
     @Deprecated
     public void removeProximityAlert(PendingIntent intent) {
@@ -1155,6 +1091,19 @@
         }
     }
 
+    /**
+     * Remove a single geofence.
+     *
+     * <p>This removes only the specified geofence associated with the
+     * specified pending intent. All other geofences remain unchanged.
+     *
+     * @param fence a geofence previously passed to {@link #addGeofence}
+     * @param intent a pending intent previously passed to {@link #addGeofence}
+     *
+     * @throws IllegalArgumentException if fence is null
+     * @throws IllegalArgumentException if intent is null
+     * @throws SecurityException if no suitable permission is present
+     */
     public void removeGeofence(Geofence fence, PendingIntent intent) {
         checkPendingIntent(intent);
         checkGeofence(fence);
@@ -1167,6 +1116,14 @@
         }
     }
 
+    /**
+     * Remove all geofences registered to the specified pending intent.
+     *
+     * @param intent a pending intent previously passed to {@link #addGeofence}
+     *
+     * @throws IllegalArgumentException if intent is null
+     * @throws SecurityException if no suitable permission is present
+     */
     public void removeAllGeofences(PendingIntent intent) {
         checkPendingIntent(intent);
         String packageName = mContext.getPackageName();
@@ -1179,16 +1136,18 @@
     }
 
     /**
-     * Returns the current enabled/disabled status of the given provider. If the
-     * user has enabled this provider in the Settings menu, true is returned
-     * otherwise false is returned
+     * Returns the current enabled/disabled status of the given provider.
+     *
+     * <p>If the user has enabled this provider in the Settings menu, true
+     * is returned otherwise false is returned
      *
      * @param provider the name of the provider
      * @return true if the provider is enabled
      *
-     * @throws SecurityException if no suitable permission is present for the provider.
      * @throws IllegalArgumentException if provider is null
-     * @deprecated use the {@link LocationRequest} class instead
+     * @throws SecurityException if no suitable permission is present
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public boolean isProviderEnabled(String provider) {
@@ -1202,19 +1161,34 @@
         }
     }
 
-    public Location getLastLocation(LocationRequest request) {
+    /**
+     * Get the last known location.
+     *
+     * <p>This location could be very old so use
+     * {@link Location#getElapsedRealtimeNano} to calculate its age. It can
+     * also return null if no previous location is available.
+     *
+     * <p>Always returns immediately.
+     *
+     * @return The last known location, or null if not available
+     * @throws SecurityException if no suitable permission is present
+     */
+    public Location getLastLocation() {
+        String packageName = mContext.getPackageName();
+
         try {
-            return mService.getLastLocation(request);
+            return mService.getLastLocation(null, packageName);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException", e);
             return null;
         }
     }
 
-
     /**
      * Returns a Location indicating the data from the last known
-     * location fix obtained from the given provider.  This can be done
+     * location fix obtained from the given provider.
+     *
+     * <p> This can be done
      * without starting the provider.  Note that this location could
      * be out-of-date, for example if the device was turned off and
      * moved to another location.
@@ -1224,46 +1198,41 @@
      * @param provider the name of the provider
      * @return the last known location for the provider, or null
      *
-     * @throws SecurityException if no suitable permission is present for the provider.
+     * @throws SecurityException if no suitable permission is present
      * @throws IllegalArgumentException if provider is null or doesn't exist
-     * @deprecated use the {@link LocationRequest} class instead
+     *
+     * @deprecated Use {@link #getLastLocation} instead
      */
     @Deprecated
     public Location getLastKnownLocation(String provider) {
         checkProvider(provider);
-
+        String packageName = mContext.getPackageName();
         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
                 provider, 0, 0, true);
 
         try {
-            return mService.getLastLocation(request);
+            return mService.getLastLocation(request, packageName);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException", e);
             return null;
         }
     }
 
-    // Mock provider support
+    // --- Mock provider support ---
+    // TODO: It would be fantastic to deprecate mock providers entirely, and replace
+    // with something closer to LocationProviderBase.java
 
     /**
      * Creates a mock location provider and adds it to the set of active providers.
      *
      * @param name the provider name
-     * @param requiresNetwork
-     * @param requiresSatellite
-     * @param requiresCell
-     * @param hasMonetaryCost
-     * @param supportsAltitude
-     * @param supportsSpeed
-     * @param supportsBearing
-     * @param powerRequirement
-     * @param accuracy
      *
      * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
      * Settings.Secure.ALLOW_MOCK_LOCATION} system setting is not enabled
      * @throws IllegalArgumentException if a provider with the given name already exists
-     * @deprecated use the {@link LocationRequest} class instead
+     *
+     * @deprecated requesting location providers by name is deprecated
      */
     @Deprecated
     public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
@@ -1292,7 +1261,8 @@
      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
      * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
      * @throws IllegalArgumentException if no provider with the given name exists
-     * @deprecated use the {@link LocationRequest} class instead
+     *
+     * @deprecated requesting location providers by name is deprecated
      */
     @Deprecated
     public void removeTestProvider(String provider) {
@@ -1318,7 +1288,8 @@
      * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
      * @throws IllegalArgumentException if no provider with the given name exists
      * @throws IllegalArgumentException if the location is incomplete
-     * @deprecated use the {@link LocationRequest} class instead
+     *
+     * @deprecated requesting location providers by name is deprecated
      */
     @Deprecated
     public void setTestProviderLocation(String provider, Location loc) {
@@ -1351,7 +1322,8 @@
      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
      * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
      * @throws IllegalArgumentException if no provider with the given name exists
-     * @deprecated use the {@link LocationRequest} class instead
+     *
+     * @deprecated requesting location providers by name is deprecated
      */
     @Deprecated
     public void clearTestProviderLocation(String provider) {
@@ -1373,7 +1345,8 @@
      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
      * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
      * @throws IllegalArgumentException if no provider with the given name exists
-     * @deprecated use the {@link LocationRequest} class instead
+     *
+     * @deprecated requesting location providers by name is deprecated
      */
     @Deprecated
     public void setTestProviderEnabled(String provider, boolean enabled) {
@@ -1393,7 +1366,8 @@
      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
      * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
      * @throws IllegalArgumentException if no provider with the given name exists
-     * @deprecated use the {@link LocationRequest} class instead
+     *
+     * @deprecated requesting location providers by name is deprecated
      */
     @Deprecated
     public void clearTestProviderEnabled(String provider) {
@@ -1417,7 +1391,8 @@
      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
      * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
      * @throws IllegalArgumentException if no provider with the given name exists
-     * @deprecated use the {@link LocationRequest} class instead
+     *
+     * @deprecated requesting location providers by name is deprecated
      */
     @Deprecated
     public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
@@ -1437,7 +1412,8 @@
      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
      * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
      * @throws IllegalArgumentException if no provider with the given name exists
-     * @deprecated use the {@link LocationRequest} class instead
+     *
+     * @deprecated requesting location providers by name is deprecated
      */
     @Deprecated
     public void clearTestProviderStatus(String provider) {
@@ -1448,7 +1424,7 @@
         }
     }
 
-    // GPS-specific support
+    // --- GPS-specific support ---
 
     // This class is used to send GPS status events to the client's main thread.
     private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {
@@ -1682,7 +1658,8 @@
      * The provider may optionally fill the extras Bundle with results from the command.
      *
      * @return true if the command succeeds.
-     * @deprecated use the {@link LocationRequest} class instead
+     *
+     * @deprecated Use {@link LocationRequest} instead, see notes on {@link LocationManager}
      */
     @Deprecated
     public boolean sendExtraCommand(String provider, String command, Bundle extras) {
@@ -1698,7 +1675,7 @@
      * Used by NetInitiatedActivity to report user response
      * for network initiated GPS fix requests.
      *
-     * {@hide}
+     * @hide
      */
     public boolean sendNiResponse(int notifId, int userResponse) {
     	try {
@@ -1720,6 +1697,7 @@
             throw new IllegalArgumentException("invalid criteria: " + criteria);
         }
     }
+
     private static void checkListener(LocationListener listener) {
         if (listener == null) {
             throw new IllegalArgumentException("invalid listener: " + listener);
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index 3110196..b1863b8 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -21,24 +21,140 @@
 import android.os.SystemClock;
 import android.util.TimeUtils;
 
+
+/**
+ * A data object that contains quality of service parameters for requests
+ * to the {@link LocationManager}.
+ *
+ * <p>LocationRequest objects are used to request a quality of service
+ * for location updates from the Location Manager.
+ *
+ * <p>For example, if your application wants high accuracy location
+ * it should create a location request with {@link #setQuality} set to
+ * {@link #ACCURACY_FINE} or {@link #POWER_HIGH}, and it should set
+ * {@link #setInterval} to less than one second. This would be
+ * appropriate for mapping applications that are showing your location
+ * in real-time.
+ *
+ * <p>At the other extreme, if you want negligible power
+ * impact, but to still receive location updates when available, then use
+ * {@link #setQuality} with {@link #POWER_NONE}. With this request your
+ * application will not trigger (and therefore will not receive any
+ * power blame) any location updates, but will receive locations
+ * triggered by other applications. This would be appropriate for
+ * applications that have no firm requirement for location, but can
+ * take advantage when available.
+ *
+ * <p>In between these two extremes is a very common use-case, where
+ * applications definitely want to receive
+ * updates at a specified interval, and can receive them faster when
+ * available, but still want a low power impact. These applications
+ * should consider {@link #POWER_LOW} combined with a faster
+ * {@link #setFastestInterval} (such as 1 minute) and a slower
+ * {@link #setInterval} (such as 60 minutes). They will only be assigned
+ * power blame for the interval set by {@link #setInterval}, but can
+ * still receive locations triggered by other applications at a rate up
+ * to {@link #setFastestInterval}. This style of request is appropriate for
+ * many location aware applications, including background usage. Do be
+ * careful to also throttle {@link #setFastestInterval} if you perform
+ * heavy-weight work after receiving an update - such as using the network.
+ *
+ * <p>Activities should strongly consider removing all location
+ * request when entering the background
+ * (for example at {@link android.app.Activity#onPause}), or
+ * at least swap the request to a larger interval and lower quality.
+ * Future version of the location manager may automatically perform background
+ * throttling on behalf of applications.
+ *
+ * <p>Applications cannot specify the exact location sources that are
+ * used by Android's <em>Fusion Engine</em>. In fact, the system
+ * may have multiple location sources (providers) running and may
+ * fuse the results from several sources into a single Location object.
+ *
+ * <p>Location requests from applications with
+ * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} and not
+ * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} will
+ * be automatically throttled to a slower interval, and the location
+ * object will be obfuscated to only show a coarse level of accuracy.
+ *
+ * <p>All location requests are considered hints, and you may receive
+ * locations that are more accurate, less accurate, and slower
+ * than requested.
+ */
 public final class LocationRequest implements Parcelable {
-    // QOS control
-    public static final int ACCURACY_FINE = 100;  // ~1 meter
-    public static final int ACCURACY_BLOCK = 102; // ~100 meters
-    public static final int ACCURACY_CITY = 104;  // ~10 km
+    /**
+     * Used with {@link #setQuality} to request the most accurate locations available.
+     *
+     * <p>This may be up to 1 meter accuracy, although this is implementation dependent.
+     */
+    public static final int ACCURACY_FINE = 100;
+
+    /**
+     * Used with {@link #setQuality} to request "block" level accuracy.
+     *
+     * <p>Block level accuracy is considered to be about 100 meter accuracy,
+     * although this is implementation dependent. Using a coarse accuracy
+     * such as this often consumes less power.
+     */
+    public static final int ACCURACY_BLOCK = 102;
+
+    /**
+     * Used with {@link #setQuality} to request "city" level accuracy.
+     *
+     * <p>City level accuracy is considered to be about 10km accuracy,
+     * although this is implementation dependent. Using a coarse accuracy
+     * such as this often consumes less power.
+     */
+    public static final int ACCURACY_CITY = 104;
+
+    /**
+     * Used with {@link #setQuality} to require no direct power impact (passive locations).
+     *
+     * <p>This location request will not trigger any active location requests,
+     * but will receive locations triggered by other applications. Your application
+     * will not receive any direct power blame for location work.
+     */
     public static final int POWER_NONE = 200;
+
+    /**
+     * Used with {@link #setQuality} to request low power impact.
+     *
+     * <p>This location request will avoid high power location work where
+     * possible.
+     */
     public static final int POWER_LOW = 201;
+
+    /**
+     * Used with {@link #setQuality} to allow high power consumption for location.
+     *
+     * <p>This location request will allow high power location work.
+     */
     public static final int POWER_HIGH = 203;
 
+    /**
+     * By default, mFastestInterval = FASTEST_INTERVAL_MULTIPLE * mInterval
+     */
+    private static final double FASTEST_INTERVAL_FACTOR = 6.0;  // 6x
+
     private int mQuality = POWER_LOW;
-    private long mFastestInterval = 6 * 1000;  // 6 seconds
-    private long mInterval = 60 * 1000;        // 1 minute
+    private long mInterval = 60 * 60 * 1000;   // 60 minutes
+    private long mFastestInterval = (long)(mInterval / FASTEST_INTERVAL_FACTOR);  // 10 minutes
+    private boolean mExplicitFastestInterval = false;
     private long mExpireAt = Long.MAX_VALUE;  // no expiry
     private int mNumUpdates = Integer.MAX_VALUE;  // no expiry
     private float mSmallestDisplacement = 0.0f;    // meters
 
     private String mProvider = null;  // for deprecated API's that explicitly request a provider
 
+    /**
+     * Create a location request with default parameters.
+     *
+     * <p>Default parameters are for a low power, slowly updated location.
+     * It can then be adjusted as required by the applications before passing
+     * to the {@link LocationManager}
+     *
+     * @return a new location request
+     */
     public static LocationRequest create() {
         LocationRequest request = new LocationRequest();
         return request;
@@ -105,52 +221,217 @@
     /** @hide */
     public LocationRequest() { }
 
+    /**
+     * Set the quality of the request.
+     *
+     * <p>Use with a accuracy constant such as {@link #ACCURACY_FINE}, or a power
+     * constant such as {@link #POWER_LOW}. You cannot request both and accuracy and
+     * power, only one or the other can be specified. The system will then
+     * maximize accuracy or minimize power as appropriate.
+     *
+     * <p>The quality of the request is a strong hint to the system for which
+     * location sources to use. For example, {@link #ACCURACY_FINE} is more likely
+     * to use GPS, and {@link #POWER_LOW} is more likely to use WIFI & Cell tower
+     * positioning, but it also depends on many other factors (such as which sources
+     * are available) and is implementation dependent.
+     *
+     * <p>{@link #setQuality} and {@link #setInterval} are the most important parameters
+     * on a location request.
+     *
+     * @param quality an accuracy or power constant
+     * @throws InvalidArgumentException if the quality constant is not valid
+     * @return the same object, so that setters can be chained
+     */
     public LocationRequest setQuality(int quality) {
         checkQuality(quality);
         mQuality = quality;
         return this;
     }
 
+    /**
+     * Get the quality of the request.
+     *
+     * @return an accuracy or power constant
+     */
     public int getQuality() {
         return mQuality;
     }
 
+    /**
+     * Set the desired interval for active location updates, in milliseconds.
+     *
+     * <p>The location manager will actively try to obtain location updates
+     * for your application at this interval, so it has a
+     * direct influence on the amount of power used by your application.
+     * Choose your interval wisely.
+     *
+     * <p>This interval is inexact. You may not receive updates at all (if
+     * no location sources are available), or you may receive them
+     * slower than requested. You may also receive them faster than
+     * requested (if other applications are requesting location at a
+     * faster interval). The fastest rate that that you will receive
+     * updates can be controlled with {@link #setFastestInterval}.
+     *
+     * <p>Applications with only the coarse location permission may have their
+     * interval silently throttled.
+     *
+     * <p>An interval of 0 is allowed, but not recommended, since
+     * location updates may be extremely fast on future implementations.
+     *
+     * <p>{@link #setQuality} and {@link #setInterval} are the most important parameters
+     * on a location request.
+     *
+     * @param millis desired interval in millisecond, inexact
+     * @throws InvalidArgumentException if the interval is less than zero
+     * @return the same object, so that setters can be chained
+     */
     public LocationRequest setInterval(long millis) {
         checkInterval(millis);
         mInterval = millis;
+        if (!mExplicitFastestInterval) {
+            mFastestInterval = (long)(mInterval / FASTEST_INTERVAL_FACTOR);
+        }
         return this;
     }
 
+    /**
+     * Get the desired interval of this request, in milliseconds.
+     *
+     * @return desired interval in milliseconds, inexact
+     */
     public long getInterval() {
         return mInterval;
     }
 
+    /**
+     * Explicitly set the fastest interval for location updates, in
+     * milliseconds.
+     *
+     * <p>This controls the fastest rate at which your application will
+     * receive location updates, which might be faster than
+     * {@link #setInterval} in some situations (for example, if other
+     * applications are triggering location updates).
+     *
+     * <p>This allows your application to passively acquire locations
+     * at a rate faster than it actively acquires locations, saving power.
+     *
+     * <p>Unlike {@link #setInterval}, this parameter is exact. Your
+     * application will never receive updates faster than this value.
+     *
+     * <p>If you don't call this method, a fastest interval
+     * will be selected for you. It will be a value faster than your
+     * active interval ({@link #setInterval}).
+     *
+     * <p>An interval of 0 is allowed, but not recommended, since
+     * location updates may be extremely fast on future implementations.
+     *
+     * <p>If {@link #setFastestInterval} is set slower than {@link #setInterval},
+     * then your effective fastest interval is {@link #setInterval}.
+     *
+     * @param millis fastest interval for updates in milliseconds, exact
+     * @throws InvalidArgumentException if the interval is less than zero
+     * @return the same object, so that setters can be chained
+     */
     public LocationRequest setFastestInterval(long millis) {
         checkInterval(millis);
+        mExplicitFastestInterval = true;
         mFastestInterval = millis;
         return this;
     }
 
+    /**
+     * Get the fastest interval of this request, in milliseconds.
+     *
+     * <p>The system will never provide location updates faster
+     * than the minimum of {@link #getFastestInterval} and
+     * {@link #getInterval}.
+     *
+     * @return fastest interval in milliseconds, exact
+     */
     public long getFastestInterval() {
         return mFastestInterval;
     }
 
+    /**
+     * Set the duration of this request, in milliseconds.
+     *
+     * <p>The duration begins immediately (and not when the request
+     * is passed to the location manager), so call this method again
+     * if the request is re-used at a later time.
+     *
+     * <p>The location manager will automatically stop updates after
+     * the request expires.
+     *
+     * <p>The duration includes suspend time. Values less than 0
+     * are allowed, but indicate that the request has already expired.
+     *
+     * @param millis duration of request in milliseconds
+     * @return the same object, so that setters can be chained
+     */
     public LocationRequest setExpireIn(long millis) {
         mExpireAt = millis + SystemClock.elapsedRealtime();
         if (mExpireAt < 0) mExpireAt = 0;
         return this;
     }
 
+    /**
+     * Set the request expiration time, in millisecond since boot.
+     *
+     * <p>This expiration time uses the same time base as {@link SystemClock#elapsedRealtime}.
+     *
+     * <p>The location manager will automatically stop updates after
+     * the request expires.
+     *
+     * <p>The duration includes suspend time. Values before {@link SystemClock#elapsedRealtime}
+     * are allowed,  but indicate that the request has already expired.
+     *
+     * @param millis expiration time of request, in milliseconds since boot including suspend
+     * @return the same object, so that setters can be chained
+     */
     public LocationRequest setExpireAt(long millis) {
         mExpireAt = millis;
         if (mExpireAt < 0) mExpireAt = 0;
         return this;
     }
 
+    /**
+     * Get the request expiration time, in milliseconds since boot.
+     *
+     * <p>This value can be compared to {@link SystemClock#elapsedRealtime} to determine
+     * the time until expiration.
+     *
+     * @return expiration time of request, in milliseconds since boot including suspend
+     */
     public long getExpireAt() {
         return mExpireAt;
     }
 
+    /**
+     * Set the number of location updates.
+     *
+     * <p>By default locations are continuously updated until the request is explicitly
+     * removed, however you can optionally request a set number of updates.
+     * For example, if your application only needs a single fresh location,
+     * then call this method with a value of 1 before passing the request
+     * to the location manager.
+     *
+     * @param numUpdates the number of location updates requested
+     * @throws InvalidArgumentException if numUpdates is 0 or less
+     * @return the same object, so that setters can be chained
+     */
+    public LocationRequest setNumUpdates(int numUpdates) {
+        if (numUpdates <= 0) throw new IllegalArgumentException("invalid numUpdates: " + numUpdates);
+        mNumUpdates = numUpdates;
+        return this;
+    }
+
+    /**
+     * Get the number of updates requested.
+     *
+     * <p>By default this is {@link Integer#MAX_VALUE}, which indicates that
+     * locations are updated until the request is explicitly removed.
+     * @return number of updates
+     */
     public int getNumUpdates() {
         return mNumUpdates;
     }
@@ -165,11 +446,6 @@
         }
     }
 
-    public LocationRequest setNumUpdates(int numUpdates) {
-        if (numUpdates < 0) throw new IllegalArgumentException("invalid numUpdates: " + numUpdates);
-        mNumUpdates = numUpdates;
-        return this;
-    }
 
     /** @hide */
     public LocationRequest setProvider(String provider) {
@@ -195,20 +471,6 @@
         return mSmallestDisplacement;
     }
 
-    /** @hide */
-    public LocationRequest applyCoarsePermissionRestrictions() {
-        switch (mQuality) {
-            case ACCURACY_FINE:
-                mQuality = ACCURACY_BLOCK;
-                break;
-        }
-        // cap fastest interval to 6 seconds
-        if (mFastestInterval < 6 * 1000) mFastestInterval = 6 * 1000;
-        // cap requested interval to 1 minute
-        if (mInterval < 60 * 1000) mInterval = 60 * 1000;
-        return this;
-    }
-
     private static void checkInterval(long millis) {
         if (millis < 0) {
             throw new IllegalArgumentException("invalid interval: " + millis);
@@ -261,10 +523,12 @@
             return new LocationRequest[size];
         }
     };
+
     @Override
     public int describeContents() {
         return 0;
     }
+
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeInt(mQuality);
diff --git a/location/java/com/android/internal/location/ProviderProperties.java b/location/java/com/android/internal/location/ProviderProperties.java
index 08aed80..def96f0 100644
--- a/location/java/com/android/internal/location/ProviderProperties.java
+++ b/location/java/com/android/internal/location/ProviderProperties.java
@@ -145,7 +145,7 @@
         parcel.writeInt(mHasMonetaryCost ? 1 : 0);
         parcel.writeInt(mSupportsAltitude ? 1 : 0);
         parcel.writeInt(mSupportsSpeed ? 1 : 0);
-        parcel.writeInt(mSupportsSpeed ? 1 : 0);
+        parcel.writeInt(mSupportsBearing ? 1 : 0);
         parcel.writeInt(mPowerRequirement);
         parcel.writeInt(mAccuracy);
     }
diff --git a/location/lib/README.txt b/location/lib/README.txt
new file mode 100644
index 0000000..400a7dd
--- /dev/null
+++ b/location/lib/README.txt
@@ -0,0 +1,30 @@
+This library (com.android.location.provider.jar) is a shared java library
+containing classes required by unbundled location providers.
+
+--- Rules of this library ---
+o This library is effectively a PUBLIC API for unbundled location providers
+  that may be distributed outside the system image. So it MUST BE API STABLE.
+  You can add but not remove. The rules are the same as for the
+  public platform SDK API.
+o This library can see and instantiate internal platform classes (such as
+  ProviderRequest.java), but it must not expose them in any public method
+  (or by extending them via inheritance). This would break clients of the
+  library because they cannot see the internal platform classes.
+
+This library is distributed in the system image, and loaded as
+a shared library. So you can change the implementation, but not
+the interface. In this way it is like framework.jar.
+
+--- Why does this library exists? ---
+
+Unbundled location providers (such as the NetworkLocationProvider)
+can not use internal platform classes.
+
+So ideally all of these classes would be part of the public platform SDK API,
+but that doesn't seem like a great idea when only applications with a special
+signature can implement this API.
+
+The compromise is this library.
+
+It wraps internal platform classes (like ProviderRequest) with a stable
+API that does not leak the internal classes.
diff --git a/location/lib/java/com/android/location/provider/GeocodeProvider.java b/location/lib/java/com/android/location/provider/GeocodeProvider.java
index 666bb02..d7a34af 100644
--- a/location/lib/java/com/android/location/provider/GeocodeProvider.java
+++ b/location/lib/java/com/android/location/provider/GeocodeProvider.java
@@ -25,12 +25,14 @@
 import java.util.List;
 
 /**
- * An abstract superclass for geocode providers that are implemented
- * outside of the core android platform.
- * Geocode providers can be implemented as services and return the result of
+ * Base class for geocode providers implemented as unbundled services.
+ *
+ * <p>Geocode providers can be implemented as services and return the result of
  * {@link GeocodeProvider#getBinder()} in its getBinder() method.
  *
- * @hide
+ * <p>IMPORTANT: This class is effectively a public API for unbundled
+ * applications, and must remain API stable. See README.txt in the root
+ * of this package for more information.
  */
 public abstract class GeocodeProvider {
 
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index 53b0cae..b0e5d2c 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -34,10 +34,22 @@
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
 
-
 /**
- * Base class for location providers implemented as services.
- * @hide
+ * Base class for location providers implemented as unbundled services.
+ *
+ * <p>The network location provider must export a service with action
+ * "com.android.location.service.v2.NetworkLocationProvider"
+ * and a valid minor version in a meta-data field on the service, and
+ * then return the result of {@link #getBinder()} on service binding.
+ *
+ * <p>The fused location provider must export a service with action
+ * "com.android.location.service.FusedLocationProvider"
+ * and a valid minor version in a meta-data field on the service, and
+ * then return the result of {@link #getBinder()} on service binding.
+ *
+ * <p>IMPORTANT: This class is effectively a public API for unbundled
+ * applications, and must remain API stable. See README.txt in the root
+ * of this package for more information.
  */
 public abstract class LocationProviderBase {
     private final String TAG;
diff --git a/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java b/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java
index c8bdda4..9ee4df21 100644
--- a/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java
+++ b/location/lib/java/com/android/location/provider/ProviderPropertiesUnbundled.java
@@ -19,9 +19,11 @@
 import com.android.internal.location.ProviderProperties;
 
 /**
- * This class is a public API for unbundled providers,
- * that hides the (hidden framework) ProviderProperties.
- * <p>Do _not_ remove public methods on this class.
+ * This class is an interface to Provider Properties for unbundled applications.
+ *
+ * <p>IMPORTANT: This class is effectively a public API for unbundled
+ * applications, and must remain API stable. See README.txt in the root
+ * of this package for more information.
  */
 public final class ProviderPropertiesUnbundled {
     private final ProviderProperties mProperties;
diff --git a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
index 3ff19ca..3605381 100644
--- a/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
+++ b/location/lib/java/com/android/location/provider/ProviderRequestUnbundled.java
@@ -23,9 +23,11 @@
 import com.android.internal.location.ProviderRequest;
 
 /**
- * This class is a public API for unbundled providers,
- * that hides the (hidden framework) ProviderRequest.
- * <p>Do _not_ remove public methods on this class.
+ * This class is an interface to Provider Requests for unbundled applications.
+ *
+ * <p>IMPORTANT: This class is effectively a public API for unbundled
+ * applications, and must remain API stable. See README.txt in the root
+ * of this package for more information.
  */
 public final class ProviderRequestUnbundled {
     private final ProviderRequest mRequest;
diff --git a/media/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp
index 4e0e0f2..4982a47 100755
--- a/media/jni/mediaeditor/VideoEditorClasses.cpp
+++ b/media/jni/mediaeditor/VideoEditorClasses.cpp
@@ -1853,6 +1853,9 @@
                             // Get the clip settings.
                             videoEditClasses_getClipSettings(pResult, pEnv, clipSettings,
                                 &pSettings->pClipList[i]);
+
+                            // Free the local references to avoid memory leaks
+                            pEnv->DeleteLocalRef(clipSettings);
                         }
                     }
                 }
@@ -1877,6 +1880,9 @@
                             // Get the transition settings.
                             videoEditClasses_getTransitionSettings(pResult, pEnv,
                                     transitionSettings, &pSettings->pTransitionList[i]);
+
+                            // Free the local references to avoid memory leaks
+                            pEnv->DeleteLocalRef(transitionSettings);
                         }
                     }
                 }
@@ -1900,6 +1906,9 @@
                             // Get the effect settings.
                             videoEditClasses_getEffectSettings(pResult, pEnv, effectSettings,
                                     &pSettings->Effects[i]);
+
+                            // Free the local references to avoid memory leaks
+                            pEnv->DeleteLocalRef(effectSettings);
                         }
                     }
                 }
diff --git a/media/jni/mediaeditor/VideoEditorJava.cpp b/media/jni/mediaeditor/VideoEditorJava.cpp
index ec8050f..bcf9099 100755
--- a/media/jni/mediaeditor/VideoEditorJava.cpp
+++ b/media/jni/mediaeditor/VideoEditorJava.cpp
@@ -387,6 +387,9 @@
                 (*pLength) = length;
             }
         }
+
+        // Delete local references to avoid memory leaks
+        pEnv->DeleteLocalRef(string);
     }
 
     // Return the string.
diff --git a/media/jni/mediaeditor/VideoEditorMain.cpp b/media/jni/mediaeditor/VideoEditorMain.cpp
index 41ec120..41c28c0 100755
--- a/media/jni/mediaeditor/VideoEditorMain.cpp
+++ b/media/jni/mediaeditor/VideoEditorMain.cpp
@@ -380,6 +380,9 @@
                     pEnv->GetIntField(object,fid);
    M4OSA_TRACE1_1("videoRotation = %d",
                     pSettings->ClipProperties.videoRotationDegrees);
+
+   // Free the local references to avoid memory leaks
+   pEnv->DeleteLocalRef(clazz);
 }
 
 static void jniPreviewProgressCallback (void* cookie, M4OSA_UInt32 msgType,
@@ -1849,7 +1852,9 @@
                 "not initialized");
             if (needToBeLoaded) {
                 getClipSetting(pEnv,properties, pContext->pEditSettings->pClipList[i]);
+                pEnv->DeleteLocalRef(properties);
             } else {
+                pEnv->DeleteLocalRef(properties);
                 goto videoEditor_populateSettings_cleanup;
             }
         }
diff --git a/media/libdrm/mobile1/src/objmng/drm_api.c b/media/libdrm/mobile1/src/objmng/drm_api.c
index 249cdbe..232d9f4 100644
--- a/media/libdrm/mobile1/src/objmng/drm_api.c
+++ b/media/libdrm/mobile1/src/objmng/drm_api.c
@@ -1478,13 +1478,13 @@
 
     if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */
         if (leftLen <= s->readBufLen) {
-            memcpy(mediaBuf, s->readBuf + s->readBufOff, leftLen);
+            memcpy(mediaBuf + readBytes, s->readBuf + s->readBufOff, leftLen);
             s->readBufOff += leftLen;
             s->readBufLen -= leftLen;
             readBytes += leftLen;
             leftLen = 0;
         } else {
-            memcpy(mediaBuf, s->readBuf + s->readBufOff, s->readBufLen);
+            memcpy(mediaBuf + readBytes, s->readBuf + s->readBufOff, s->readBufLen);
             s->readBufOff += s->readBufLen;
             leftLen -= s->readBufLen;
             readBytes += s->readBufLen;
diff --git a/media/mca/filterpacks/java/android/filterpacks/videosrc/MediaSource.java b/media/mca/filterpacks/java/android/filterpacks/videosrc/MediaSource.java
index 9c40cec..0be6c62 100644
--- a/media/mca/filterpacks/java/android/filterpacks/videosrc/MediaSource.java
+++ b/media/mca/filterpacks/java/android/filterpacks/videosrc/MediaSource.java
@@ -35,6 +35,7 @@
 import android.filterfw.format.ImageFormat;
 import android.graphics.SurfaceTexture;
 import android.media.MediaPlayer;
+import android.net.Uri;
 import android.os.ConditionVariable;
 import android.opengl.Matrix;
 import android.view.Surface;
@@ -64,6 +65,12 @@
     @GenerateFieldPort(name = "sourceAsset", hasDefault = true)
     private AssetFileDescriptor mSourceAsset = null;
 
+    /** The context for the MediaPlayer to resolve the sourceUrl.
+     * Make sure this is set before the sourceUrl to avoid unexpected result.
+     * If the sourceUrl is not a content URI, it is OK to keep this as null. */
+    @GenerateFieldPort(name = "context", hasDefault = true)
+    private Context mContext = null;
+
     /** Whether the media source is a URL or an asset file descriptor. Defaults
      * to false.
      */
@@ -459,7 +466,11 @@
         try {
             if (useUrl) {
                 if (mLogVerbose) Log.v(TAG, "Setting MediaPlayer source to URI " + mSourceUrl);
-                mMediaPlayer.setDataSource(mSourceUrl);
+                if (mContext == null) {
+                    mMediaPlayer.setDataSource(mSourceUrl);
+                } else {
+                    mMediaPlayer.setDataSource(mContext, Uri.parse(mSourceUrl.toString()));
+                }
             } else {
                 if (mLogVerbose) Log.v(TAG, "Setting MediaPlayer source to asset " + mSourceAsset);
                 mMediaPlayer.setDataSource(mSourceAsset.getFileDescriptor(), mSourceAsset.getStartOffset(), mSourceAsset.getLength());
diff --git a/opengl/java/com/google/android/gles_jni/GLImpl.java b/opengl/java/com/google/android/gles_jni/GLImpl.java
index 07f9e91..6b23be9 100644
--- a/opengl/java/com/google/android/gles_jni/GLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/GLImpl.java
@@ -23,7 +23,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.os.Build;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.Log;
 
 import java.nio.Buffer;
@@ -68,7 +68,7 @@
         int version = 0;
         IPackageManager pm = AppGlobals.getPackageManager();
         try {
-            ApplicationInfo applicationInfo = pm.getApplicationInfo(appName, 0, UserId.myUserId());
+            ApplicationInfo applicationInfo = pm.getApplicationInfo(appName, 0, UserHandle.myUserId());
             if (applicationInfo != null) {
                 version = applicationInfo.targetSdkVersion;
             }
diff --git a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java
index 436e579..f11b499 100644
--- a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java
+++ b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java
@@ -119,7 +119,7 @@
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
                 | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
-        if (ActivityManager.isHighEndGfx(display)) {
+        if (ActivityManager.isHighEndGfx()) {
             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         }
         lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
index 38a6091..1c22c7a 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
@@ -22,7 +22,6 @@
 
 import com.android.location.provider.ProviderRequestUnbundled;
 
-
 import android.content.Context;
 import android.location.Location;
 import android.location.LocationListener;
diff --git a/packages/SettingsProvider/res/values-ms/defaults.xml b/packages/SettingsProvider/res/values-ms/defaults.xml
new file mode 100644
index 0000000..f8c3de3
--- /dev/null
+++ b/packages/SettingsProvider/res/values-ms/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_screensaver_component" msgid="2880543806753704722">"com.google.android.deskclock/com.android.deskclock.Screensaver"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-pt/defaults.xml b/packages/SettingsProvider/res/values-pt/defaults.xml
new file mode 100644
index 0000000..f8c3de3
--- /dev/null
+++ b/packages/SettingsProvider/res/values-pt/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_screensaver_component" msgid="2880543806753704722">"com.google.android.deskclock/com.android.deskclock.Screensaver"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-zh-rCN/defaults.xml b/packages/SettingsProvider/res/values-zh-rCN/defaults.xml
new file mode 100644
index 0000000..f8c3de3
--- /dev/null
+++ b/packages/SettingsProvider/res/values-zh-rCN/defaults.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="def_screensaver_component" msgid="2880543806753704722">"com.google.android.deskclock/com.android.deskclock.Screensaver"</string>
+</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 4552a55..1481eb2 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -38,7 +38,6 @@
 import android.util.Log;
 
 import com.android.internal.content.PackageHelper;
-import com.android.internal.telephony.BaseCommands;
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.RILConstants;
@@ -65,7 +64,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 80;
+    private static final int DATABASE_VERSION = 81;
 
     private Context mContext;
 
@@ -1073,9 +1072,55 @@
             upgradeVersion = 79;
         }
 
+        if (upgradeVersion == 79) {
+            // Before touch exploration was a global setting controlled by the user
+            // via the UI. However, if the enabled accessibility services do not
+            // handle touch exploration mode, enabling it makes no sense. Therefore,
+            // now the services request touch exploration mode and the user is
+            // presented with a dialog to allow that and if she does we store that
+            // in the database. As a result of this change a user that has enabled
+            // accessibility, touch exploration, and some accessibility services
+            // may lose touch exploration state, thus rendering the device useless
+            // unless sighted help is provided, since the enabled service(s) are
+            // not in the list of services to which the user granted a permission
+            // to put the device in touch explore mode. Here we are allowing all
+            // enabled accessibility services to toggle touch exploration provided
+            // accessibility and touch exploration are enabled and no services can
+            // toggle touch exploration. Note that the user has already manually
+            // enabled the services and touch exploration which means the she has
+            // given consent to have these services work in touch exploration mode.
+            final boolean accessibilityEnabled = getIntValueFromTable(db, "secure",
+                    Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
+            final boolean touchExplorationEnabled = getIntValueFromTable(db, "secure",
+                    Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1;
+            if (accessibilityEnabled && touchExplorationEnabled) {
+                String enabledServices = getStringValueFromTable(db, "secure",
+                        Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "");
+                String touchExplorationGrantedServices = getStringValueFromTable(db, "secure",
+                        Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES, "");
+                if (TextUtils.isEmpty(touchExplorationGrantedServices)
+                        && !TextUtils.isEmpty(enabledServices)) {
+                    SQLiteStatement stmt = null;
+                    try {
+                        db.beginTransaction();
+                        stmt = db.compileStatement("INSERT OR REPLACE INTO secure(name,value)"
+                                + " VALUES(?,?);");
+                        loadSetting(stmt,
+                                Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
+                                enabledServices);
+                        db.setTransactionSuccessful();
+                    } finally {
+                        db.endTransaction();
+                        if (stmt != null) stmt.close();
+                    }
+                }
+            }
+            upgradeVersion = 80;
+        }
+
         // vvv Jelly Bean MR1 changes begin here vvv
 
-        if (upgradeVersion == 79) {
+        if (upgradeVersion == 80) {
             // update screensaver settings
             db.beginTransaction();
             SQLiteStatement stmt = null;
@@ -1093,10 +1138,9 @@
                 db.endTransaction();
                 if (stmt != null) stmt.close();
             }
-            upgradeVersion = 80;
+            upgradeVersion = 81;
         }
 
-
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
@@ -1743,18 +1787,28 @@
     }
 
     private int getIntValueFromSystem(SQLiteDatabase db, String name, int defaultValue) {
-        int value = defaultValue;
+        return getIntValueFromTable(db, "system", name, defaultValue);
+    }
+
+    private int getIntValueFromTable(SQLiteDatabase db, String table, String name,
+            int defaultValue) {
+        String value = getStringValueFromTable(db, table, name, null);
+        return (value != null) ? Integer.parseInt(value) : defaultValue;
+    }
+
+    private String getStringValueFromTable(SQLiteDatabase db, String table, String name,
+            String defaultValue) {
         Cursor c = null;
         try {
-            c = db.query("system", new String[] { Settings.System.VALUE }, "name='" + name + "'",
+            c = db.query(table, new String[] { Settings.System.VALUE }, "name='" + name + "'",
                     null, null, null, null);
             if (c != null && c.moveToFirst()) {
                 String val = c.getString(0);
-                value = val == null ? defaultValue : Integer.parseInt(val);
+                return val == null ? defaultValue : val;
             }
         } finally {
             if (c != null) c.close();
         }
-        return value;
+        return defaultValue;
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 18e7faa..9208cae 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -109,7 +109,7 @@
             IPowerManager power = IPowerManager.Stub.asInterface(
                     ServiceManager.getService("power"));
             if (power != null) {
-                power.setBacklightBrightness(brightness);
+                power.setTemporaryScreenBrightnessSettingOverride(brightness);
             }
         } catch (RemoteException doe) {
 
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 51dc3b1..2eee31d 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -15,6 +15,8 @@
     <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
     <uses-permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK" />
 
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
+
     <!-- Networking and telephony -->
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
@@ -130,6 +132,14 @@
             android:excludeFromRecents="true">
         </activity>
 
+        <!-- started from UsbDebuggingManager -->
+        <activity android:name=".usb.UsbDebuggingActivity"
+            android:permission="android.permission.MANAGE_USB"
+            android:theme="@*android:style/Theme.Holo.Dialog.Alert"
+            android:finishOnCloseSystemDialogs="true"
+            android:excludeFromRecents="true">
+        </activity>
+
         <!-- started from NetworkPolicyManagerService -->
         <activity
             android:name=".net.NetworkOverLimitActivity"
diff --git a/packages/SystemUI/res/drawable-nodpi/qs_coming_soon.png b/packages/SystemUI/res/drawable-nodpi/qs_coming_soon.png
new file mode 100644
index 0000000..47c89b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/qs_coming_soon.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml b/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml
index c478334..b68632a 100644
--- a/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/super_status_bar.xml
@@ -31,10 +31,22 @@
         android:layout_height="@*android:dimen/status_bar_height"
         />
 
-    <include layout="@layout/status_bar_expanded"
-        android:layout_width="@dimen/notification_panel_width"
-        android:layout_height="0dp"
-        android:layout_gravity="center_horizontal|top"
-        />
 
+    <com.android.systemui.statusbar.phone.PanelHolder
+        android:id="@+id/panel_holder"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="@*android:dimen/status_bar_height"
+        >
+        <include layout="@layout/status_bar_expanded"
+            android:layout_width="@dimen/notification_panel_width"
+            android:layout_height="wrap_content"
+            android:layout_gravity="left|top"
+            />
+        <include layout="@layout/quick_settings"
+            android:layout_width="@dimen/notification_panel_width"
+            android:layout_height="wrap_content"
+            android:layout_gravity="right|top"
+            />
+    </com.android.systemui.statusbar.phone.PanelHolder>
 </com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/layout/quick_settings.xml b/packages/SystemUI/res/layout/quick_settings.xml
new file mode 100644
index 0000000..c4b881e
--- /dev/null
+++ b/packages/SystemUI/res/layout/quick_settings.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<com.android.systemui.statusbar.phone.SettingsPanelView 
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:id="@+id/settings_panel"
+    >
+    <ImageView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:scaleType="centerInside"
+        android:src="@drawable/qs_coming_soon"
+        android:padding="4dp"
+        android:background="#80000080"
+        />
+    <LinearLayout android:id="@+id/handle"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/close_handle_height"
+        android:layout_gravity="bottom"
+        android:orientation="vertical"
+        >
+        <ImageView
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/close_handle_height"
+            android:layout_gravity="bottom"
+            android:scaleType="fitXY"
+            android:src="@drawable/status_bar_close"
+            />
+    </LinearLayout>
+</com.android.systemui.statusbar.phone.SettingsPanelView >
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 5841978..cb32d63 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -18,15 +18,16 @@
 */
 -->
 
-<FrameLayout 
+<com.android.systemui.statusbar.phone.NotificationPanelView 
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/notification_panel"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_width="0dp"
+    android:layout_height="wrap_content"
     android:background="@drawable/notification_panel_bg"
     android:paddingTop="@dimen/notification_panel_padding_top"
     android:layout_marginLeft="@dimen/notification_panel_margin_left"
+    android:animateLayoutChanges="true"
     >
 
     <TextView
@@ -42,9 +43,10 @@
 
     <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         android:layout_marginBottom="@dimen/close_handle_underlap"
         android:orientation="vertical"
+	    android:animateLayoutChanges="true"
         >
 
         <include layout="@layout/status_bar_expanded_header"
@@ -65,7 +67,7 @@
         <ScrollView
             android:id="@+id/scroll"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
+            android:layout_height="wrap_content"
             android:fadingEdge="none"
             android:overScrollMode="always"
             >
@@ -78,7 +80,7 @@
         </ScrollView>
     </LinearLayout>
 
-    <com.android.systemui.statusbar.phone.CloseDragHandle android:id="@+id/close"
+    <LinearLayout android:id="@+id/handle"
         android:layout_width="match_parent"
         android:layout_height="@dimen/close_handle_height"
         android:layout_gravity="bottom"
@@ -91,6 +93,5 @@
             android:scaleType="fitXY"
             android:src="@drawable/status_bar_close"
             />
-
-    </com.android.systemui.statusbar.phone.CloseDragHandle>
-</FrameLayout><!-- end of sliding panel -->
+    </LinearLayout>
+</com.android.systemui.statusbar.phone.NotificationPanelView><!-- end of sliding panel -->
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 7f598b6..60896c3 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -65,11 +65,24 @@
         android:layout_weight="1"
         />
 
+    <TextView
+        android:id="@+id/header_debug_info"
+        android:visibility="invisible"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:fontFamily="sans-serif-condensed"
+        android:textSize="11dp"
+        android:textStyle="bold"
+        android:textColor="#00A040"
+        android:padding="2dp"
+        />
+    
     <ImageView android:id="@+id/clear_all_button"
         android:layout_width="48dp"
         android:layout_height="48dp"
         android:scaleType="center"
         android:src="@drawable/ic_notify_clear"
         android:contentDescription="@string/accessibility_clear_all"
-        />            
-</LinearLayout>
\ No newline at end of file
+        />     
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index dd70166..3dcdae8 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -49,4 +49,17 @@
         android:background="@drawable/bottom_divider_glow"
         />
 
+    <TextView
+        android:id="@+id/debug_info"
+        android:visibility="invisible"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom|right"
+        android:fontFamily="sans-serif-condensed"
+        android:textSize="9dp"
+        android:textStyle="bold"
+        android:textColor="#00A040"
+        android:padding="2dp"
+        />
+
 </FrameLayout>
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 5bf1a58..ad6b8f4 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -32,9 +32,20 @@
         android:layout_height="@*android:dimen/status_bar_height"
         />
 
-    <include layout="@layout/status_bar_expanded"
+    <com.android.systemui.statusbar.phone.PanelHolder
+        android:id="@+id/panel_holder"
         android:layout_width="match_parent"
-        android:layout_height="0dp"
-        />
+        android:layout_height="match_parent"
+        android:layout_marginTop="@*android:dimen/status_bar_height"
+        >
+        <include layout="@layout/status_bar_expanded"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            />
+        <include layout="@layout/quick_settings"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            />
+    </com.android.systemui.statusbar.phone.PanelHolder>
 
 </com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 2db520a..b63ed4a 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Sien"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Gebruik by verstek vir hierdie USB-toestel"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Gebruik by verstek vir hierdie USB-toebehoorsel"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoem om skerm te vul"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Strek om skerm te vul"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Versoenbaarheidszoem"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 93547c1..0d41cc7 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"ዕይታ"</string>
     <string name="always_use_device" msgid="1450287437017315906">"ለዚህ USB  መሣሪያ በነባሪነት ተጠቀም"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"ለዚህ USB  ተቀጥላ በነባሪነት ተጠቀም"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"የUSB ማረሚያ ይፈቀድ?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"የUSB ማረም ከዚህ ኮምፒውተር ይፈቀድ?"\n"የእርስዎ RSA ቁልፍ ጣት አሻራ "\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g> ነው"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"ለዚህ ኮምፒውተር ሁልጊዜ ፍቀድ"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"ማያ እንዲሞላ አጉላ"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"ማያ ለመሙለት ሳብ"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"የተኳኋኝነት አጉላ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 9b975fe..d3d4c7f 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"عرض"</string>
     <string name="always_use_device" msgid="1450287437017315906">"الاستخدام بشكل افتراضي لجهاز USB هذا"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"الاستخدام بشكل افتراضي لملحق USB هذا"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"تكبير/تصغير لملء الشاشة"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"توسيع بملء الشاشة"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"تكبير/تصغير التوافق"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index a8a17f0..8216e2b 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"Прагляд"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Выкарыстоўваць налады па змаўчанні для дадзенай USB-прылады"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Выкарыстоўваць налады па змаўчанні для дадзенай USB-прылады"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"Дазволіць адладку USB?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"Дазволіць USB-адладку з гэтага камп\'ютара?"\n"Ваш адбiтак ключа RSA"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Дазваляць гэтаму камп\'ютару"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Павял. на ўвесь экран"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Расцягн. на ўвесь экран"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Маштабаванне для сумяшчальнасцi"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 0270678..ba57e91 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Преглед"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Използване по подразб. за това USB устройство"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Използване по подразб. за този аксесоар за USB"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Мащаб – запълва екрана"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Разпъване – запълва екрана"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Промяна на мащаба за съвместимост"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 2e48570..3eb078d 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"Mostra"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Utilitza de manera predet. per al dispositiu USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Utilitza de manera predet. per a l\'accessori USB"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"Vols permetre la depuració USB?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"Vols permetre la depuració USB des d\'aquest equip?"\n"L\'empremta de la teva clau RSA és"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Dóna sempre permís a aquest equip"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom per omplir pantalla"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Estira per omplir pant."</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilitat"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index c9b6a522..fb6584e 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Zobrazit"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Pro toto zařízení USB použít jako výchozí"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Pro toto periferní zařízení USB použít jako výchozí"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Přiblížit na celou obrazovku"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Na celou obrazovku"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Úprava velikosti z důvodu kompatibility"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 370865c..48cab36 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"Vis"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Brug som standard til denne USB-enhed"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Brug som standard til dette USB-tilbehør"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"Vil du tillade USB-fejlretning?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"Vil du tillade USB-fejlretning fra denne computer?"\n"Dit fingeraftryk for RSA-nøglen er"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Tillad altid denne computer"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom til fuld skærm"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Stræk til fuld skærm"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Kompatibilitetszoom"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 65c870f..4bcbc31 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"Anzeigen"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Standardmäßig für dieses USB-Gerät verwenden"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Standardmäßig für dieses USB-Zubehör verwenden"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"USB-Debugging zulassen?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"USB-Debugging auf diesem Computer zulassen?"\n"Ihr Fingerabdruck des RSA-Schlüssels lautet"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>."</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Auf diesem Computer immer zulassen"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom auf Bildschirmgröße"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Auf Bildschirmgröße anpassen"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Kompatibilitätszoom"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 6e147e2..2231a8c 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"Προβολή"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Χρήση από προεπιλογή για αυτή τη συσκευή USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Χρήση από προεπιλογή για αυτό το εξάρτημα USB"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"Να επιτρέπεται ο εντοπισμός σφαλμάτων USB;"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"Να επιτρέπεται ο εντοπισμός σφαλμάτων USB από αυτόν τον υπολογιστή;"\n"Το αποτύπωμα κλειδιού σας RSA είναι"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Να επιτρέπεται πάντα σε αυτόν τον υπολογιστή"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Ζουμ σε πλήρη οθόνη"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Προβoλή σε πλήρη οθ."</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Ζουμ για συμβατότητα"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index afabd34..671ac1b 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"View"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Use by default for this USB device"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Use by default for this USB accessory"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"Allow USB Debugging?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"Allow USB Debugging from this computer?"\n"Your RSA key fingerprint is"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Always allow this computer"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom to fill screen"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Stretch to fill screen"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Compatibility zoom"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index b83aad5..4c07d9f 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Ver"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Se usa de forma predeterminada para este dispositivo USB."</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Se usa de forma predeterminada para este accesorio USB."</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom para ocupar la pantalla"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Estirar p/ ocupar la pantalla"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilidad"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index c0cab22..cd03d92 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"Ver"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Usar de forma predeterminada para este dispositivo USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Usar de forma predeterminada para este accesorio USB"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"¿Permitir depuración USB?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"¿Quieres permitir la depuración USB en este ordenador?"\n"La huella digital de tu clave RSA es:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Permitir siempre en este ordenador"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom para ajustar"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Expandir para ajustar"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilidad"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 8adf8ed..17484377 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Kuva"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Kasuta vaikimisi selle USB-seadme jaoks"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Vaikimisi kasuta seda USB-lisaseadet"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Suumi ekraani täitmiseks"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Venita ekraani täitmiseks"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Sobivussuum"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 2c66897..e75d5f0 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"مشاهده"</string>
     <string name="always_use_device" msgid="1450287437017315906">"استفاده به صورت پیش‌فرض برای این دستگاه USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"استفاده به صورت پیش‌فرض برای این دستگاه USB"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"بزرگنمایی برای پر کردن صفحه"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"گسترده کردن برای پر کردن صفحه"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"بزرگنمایی سازگاری"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index bec1b48..5132502 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"Näytä"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Käytä oletuksena tällä USB-laitteella"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Käytä oletuksena tällä USB-lisälaitteella"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"Sallitaanko USB-vianetsintä?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"Sallitaanko USB-vianetsintä tällä tietokoneella?"\n"RSA-avaimesi sormenjälki on"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Salli vianetsintä tällä tietokoneella aina"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoomaa koko näyttöön"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Venytä koko näyttöön"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Yhteensopivuuszoomaus"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 15489f5a..d862df8 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Afficher"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Utiliser par défaut pour ce périphérique USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Utiliser par défaut pour cet accessoire USB"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoomer pour remplir l\'écran"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Étirer pour remplir l\'écran"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilité"</string>
@@ -135,7 +141,7 @@
     <string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Données désactivées"</string>
     <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Vous avez atteint le plafond de consommation de données spécifié."\n\n"Si vous utilisez des données supplémentaires, celles-ci pourront être facturées par l\'opérateur."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Réactiver connexion données"</string>
-    <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion"</string>
+    <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Recherche de GPS..."</string>
     <string name="gps_notification_found_text" msgid="4619274244146446464">"Position définie par GPS"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index c66b680..b45b4ce 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"देखें"</string>
     <string name="always_use_device" msgid="1450287437017315906">"इस USB उपकरण के लिए डिफ़ॉल्‍ट रूप से उपयोग करें"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"इस USB एसेसरी के लिए डिफ़ॉल्‍ट रूप से उपयोग करें"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"स्‍क्रीन भरने हेतु ज़ूम करें"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"स्‍क्रीन को भरने के लिए खींचें"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"संगतता ज़ूम"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 1a10ecb..620e193 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Prikaži"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Koristi se prema zadanim postavkama za ovaj USB uređaj"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Koristi se prema zadanim postavkama za ovaj USB pribor"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Zumiraj i ispuni zaslon"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Rastegni i ispuni zaslon"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Kompatibilno zumiranje"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 25f3e54..1805ce0 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Megtekintés"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Alapértelmezett használat ehhez az USB-eszközhöz"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Alapértelmezett használat ehhez az USB-kiegészítőhöz"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Nagyítás a kitöltéshez"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Nyújtás kitöltéshez"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Kompatibilitás -- nagyítás/kicsinyítés"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 3ad4fd1..65e47dd 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"Lihat"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Gunakan secara default untuk perangkat USB ini"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Gunakan secara default untuk aksesori USB ini"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"Izinkan Debugging USB?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"Izinkan Debugging USB dari komputer ini?"\n"Sidik jari kunci RSA Anda adalah"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Selalu izinkan komputer ini"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Perbesar utk mengisi layar"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Rentangkn utk mngisi layar"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Perbesar/perkecil untuk kompatibilitas"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index df7f188..49b0fb0 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"Visualizza"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Usa per impostazione predef. per dispositivo USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Usa per impostazione predef. per accessorio USB"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"Consentire debug USB?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"Consentire il debug USB da questo computer? "\n"La fingerprint della tua chiave RSA è "\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Consenti sempre da questo computer"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom per riempire schermo"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Estendi per riemp. schermo"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom compatibilità"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 2e75e72..59730af 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"הצג"</string>
     <string name="always_use_device" msgid="1450287437017315906">"השתמש כברירת מחדל עבור מכשיר USB זה"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"השתמש כברירת מחדל עבור אביזר USB זה"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"האם לאפשר ניקוי באגים ב-USB?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"האם להרשות ניקוי באגים ב-USB ממחשב זה?"\n"טביעת האצבע של מפתח ה-RSA שלך היא"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"הרשה תמיד במחשב זה"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"הגדל תצוגה כדי למלא את המסך"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"מתח כדי למלא את המסך"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"שינוי מרחק מתצוגה לצורך תאימות"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 2d73518..8eda13f 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"表示"</string>
     <string name="always_use_device" msgid="1450287437017315906">"このUSBデバイスにデフォルトで使用する"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"このUSBアクセサリにデフォルトで使用する"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"画面サイズに合わせて拡大"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"画面サイズに合わせて拡大"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"互換ズーム"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 438734e..9562237c 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"보기"</string>
     <string name="always_use_device" msgid="1450287437017315906">"이 USB 기기에 기본값으로 사용"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"이 USB 액세서리에 기본값으로 사용"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"전체화면 모드로 확대"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"전체화면 모드로 확대"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"호환성 확대/축소"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 62c6a06..daacca55 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Žiūrėti"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Šiam USB įreng. naudoti pagal numat. nustatymus"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Šiam USB priedui naudoti pagal numat. nustatymus"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Keisti mast., kad atit. ekr."</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Ištempti, kad atit. ekr."</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Suderinamumo mastelio keitimas"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 5929240..b189fd2 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Skatīt"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Pēc noklusējuma izmantot šai USB ierīcei"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Pēc noklusējuma izmantot šim USB piederumam"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Tālumm., lai aizp. ekr."</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Stiepiet, lai aizp. ekr."</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Saderības tālummaiņa"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 5bf9811..8da9ed5 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Lihat"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Gunakan secara lalai untuk peranti USB ini"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Gunakan secara lalai untuk aksesori USB ini"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Zum untuk memenuhi skrin"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Regang utk memenuhi skrin"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Zum keserasian"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 9a0b2de..e7005fa 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"Vis"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Bruk som standard for denne USB-enheten"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Bruk som standard for dette USB-tilbehøret"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"Vil du tillate USB-feilsøking?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"Vil du tillate USB-feilsøking fra denne datamaskinen?"\n"Nøkkelfingeravtrykket ditt for RSA er"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Gi alltid tillatelse til denne datamaskinen"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom for å fylle skjermen"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Strekk for å fylle skjerm"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Kompatibilitets-zooming"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 33bab76..d5e8444 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"Weergeven"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Standaard gebruiken voor dit USB-apparaat"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Standaard gebruiken voor dit USB-accessoire"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"USB-foutopsporing toestaan?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"USB-foutopsporing toestaan vanaf deze computer?"\n"Uw RSA-sleutelvingerafdruk is"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Deze computer altijd toestaan"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom om scherm te vullen"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Rek uit v. schermvulling"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Compatibiliteitszoom"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 6a7639f..50d5e3b 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Wyświetl"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Używaj domyślnie dla tego urządzenia USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Używaj domyślnie dla tego akcesorium USB"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Powiększ, aby wypełnić ekran"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Rozciągnij, aby wypełnić ekran"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Powiększenie w trybie zgodności"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 655c46e..b583aea 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Ver"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Utilizar por predefinição para este aparelho USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Utilizar por predefinição para este acessório USB"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom para preencher o ecrã"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Esticar p. caber em ec. int."</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilidade"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 5fabdfd..bae61d0 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Visualizar"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Usar por padrão para este dispositivo USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Usar por padrão para este acessório USB"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom p/ preencher a tela"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Ampliar p/ preencher tela"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom em modo de compatibilidade"</string>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index e0c0886..ea88ddd 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -86,6 +86,12 @@
     <skip />
     <!-- no translation found for always_use_accessory (1210954576979621596) -->
     <skip />
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <!-- no translation found for compat_mode_on (6623839244840638213) -->
     <skip />
     <!-- no translation found for compat_mode_off (4434467572461327898) -->
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 58a9a9b..5580f01 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Afişaţi"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Utilizaţi în mod prestabilit pt. acest dispoz. USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Utiliz. în mod prestabilit pt. acest accesoriu USB"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Zoom pt. a umple ecranul"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Înt. pt. a umple ecranul"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom de compatibilitate"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 155238a..567d1de 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -25,7 +25,7 @@
     <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Показать уведомления"</string>
     <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Удаление из списка"</string>
     <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"О приложении"</string>
-    <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Нет данных"</string>
+    <string name="status_bar_no_recent_apps" msgid="6576392951053994640">"В последнее время вы не запускали приложения."</string>
     <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Закрыть недавние приложения"</string>
   <plurals name="status_bar_accessibility_recent_apps">
     <item quantity="one" msgid="5854176083865845541">"Недавних приложений: 1"</item>
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Просмотр"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Использовать по умолчанию для этого USB-устройства"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Использовать по умолчанию для этого USB-аксессуара"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Подогнать по размерам экрана"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Растянуть на весь экран"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Масштаб и совместимость"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 0c15f6c..01a8606 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Zobraziť"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Pre toto zariadenie USB použiť ako predvolené"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Pre toto periférne zar. USB použiť ako predvolené"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Priblížiť na celú obrazovku"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Na celú obrazovku"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Úprava veľkosti z dôvodu kompatibility"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 2b385fc..1bed89b 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"Prikaži"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Privzeto uporabi za to napravo USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Privzeto uporabi za ta dodatek USB"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"Ali dovolite odpravljanje težav s povezavo USB?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"Ali dovolite odpravljanje težav s povezavo USB v tem računalniku?"\n"Prstni odtis ključa RSA je"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Vedno dovoli za ta računalnik"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Povečava čez cel zaslon"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Raztegnitev čez zaslon"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Razširitev združljivosti"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index c43b66f..3987d76 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Прикажи"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Користи подразумевано за овај USB уређај"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Користи подразумевано за овај USB додатак"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Зумирај на целом екрану"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Развуци на цео екран"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Компатибилно зумирање"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index e3a1481..f09dc2a 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"Visa"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Använd som standard för den här USB-enheten"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Använd som standard för det här USB-tillbehöret"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"Ska USB-felsökning tillåtas?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"Vill du tillåta USB-felsökning från den här datorn?"\n"Din RSA-fingeravtrycksnyckel är"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Tillåt alltid för den här datorn"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Zooma för att fylla skärm"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Dra för att fylla skärmen"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom i kompatibilitetsläge"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index b333bbe..a6fec13 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -56,6 +56,9 @@
     <string name="label_view" msgid="6304565553218192990">"Ona"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Kwa kifaa hiki cha USB tumia chaguo-msingi"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Tumia kama chaguo-msingi ya kifuasi hiki cha USB"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"Ruhusu Utatuaji USB?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"Ruhusu Utatuaji wa USB kutoka kwenye kompyuta hii?"\n"Kitufe chako RSA cha alama ya kidole ni "\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Kila wakati ruhusu kompyuta hii"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Kuza ili kujaza skrini"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Tanua ili kujaza skrini"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Kukuza kwa Utangamanifu"</string>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index afa0b20..c6c0719 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -19,8 +19,4 @@
     <!-- Layout parameters for the notification panel -->
 	<dimen name="notification_panel_margin_bottom">0dp</dimen>
     <dimen name="notification_panel_margin_left">32dp</dimen>
-
-    <!-- Gravity for the notification panel -->
-    <!-- 0x33 = left|top -->
-    <integer name="notification_panel_layout_gravity">0x33</integer>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 2b5248f..b6faff3 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -21,11 +21,12 @@
 
     <!-- Layout parameters for the notification panel -->
     <dimen name="notification_panel_margin_bottom">192dp</dimen>
-    <dimen name="notification_panel_margin_left">0dp</dimen>
+    <dimen name="notification_panel_margin_left">16dp</dimen>
 
-    <!-- Gravity for the notification panel -->
-    <!-- 0x33 = center_horizontal|top -->
-    <integer name="notification_panel_layout_gravity">0x31</integer>
+    <!-- Gravity for the notification & quick settings panels -->
+    <!-- 0x33 = left|top ; 0x35 = right|top -->
+    <integer name="notification_panel_layout_gravity">0x33</integer>
+    <integer name="settings_panel_layout_gravity">0x35</integer>
 
     <!-- Diameter of outer shape drawable shown in navbar search-->
     <dimen name="navbar_search_outerring_diameter">430dip</dimen>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 4d46a5d..0c42f87 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"ดู"</string>
     <string name="always_use_device" msgid="1450287437017315906">"ใช้ค่าเริ่มต้นสำหรับอุปกรณ์ USB นี้"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"ใช้ค่าเริ่มต้นสำหรับอุปกรณ์เสริม USB นี้"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"ขยายจนเต็มหน้าจอ"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"ยืดจนเต็มหน้าจอ"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"ความเข้ากันได้ของการย่อ/ขยาย"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index a93e511..bb0a2bf 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Tingnan"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Gamitin bilang default para sa USB device"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Gamitin bilang default sa USB accessory na ito"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"I-zoom upang punan screen"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"I-stretch upang mapuno screen"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Zoom sa pagiging Tugma"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 0f6af69..6c30abe 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Görüntüle"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Bu USB cihazı için varsayılan olarak kullan"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Bu USB aksesuar için varsayılan olarak kullan"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Yakınlaştır (ekranı kaplasın)"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Genişlet (ekran kapansın)"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Uyumluluk yakınlaştırması"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 5922e24..973c6bc 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -58,6 +58,9 @@
     <string name="label_view" msgid="6304565553218192990">"Переглянути"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Використовувати за умовчанням для пристрою USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Використовувати за умовчанням для аксесуара USB"</string>
+    <string name="usb_debugging_title" msgid="1114766024068112429">"Дозволити налагодження USB?"</string>
+    <string name="usb_debugging_message" msgid="719863946976291180">"Дозволити налагодження USB на цьому комп’ютері?"\n"Цифровий відбиток вашого ключа RSA:"\n"<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+    <string name="usb_debugging_always" msgid="4253099426793114693">"Завжди дозволяти цьому комп’ютеру"</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Масштабув. на весь екран"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Розтягнути на весь екран"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Масштабування для сумісності"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 15141c9..cef38ecb 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Xem"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Sử dụng theo mặc định cho thiết bị USB này"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Sử dụng theo mặc định cho phụ kiện USB này"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"T.phóng để lấp đầy m.hình"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Giãn ra để lấp đầy m.hình"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Thu phóng tương thích"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 19470e6..d0f4a9c 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"查看"</string>
     <string name="always_use_device" msgid="1450287437017315906">"默认情况下用于该 USB 设备"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"默认情况下用于该 USB 配件"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"缩放以填满屏幕"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"拉伸以填满屏幕"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"兼容性缩放"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index fa2e9d1..2e5211f 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"查看"</string>
     <string name="always_use_device" msgid="1450287437017315906">"預設用於這個 USB 裝置"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"預設用於這個 USB 配件"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"放大為全螢幕"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"放大為全螢幕"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"相容性縮放"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 1e11f04..07c9f0f 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -58,6 +58,12 @@
     <string name="label_view" msgid="6304565553218192990">"Buka"</string>
     <string name="always_use_device" msgid="1450287437017315906">"Sebenzisa ngokuzenzakalelayo yale divayisi ye-USB"</string>
     <string name="always_use_accessory" msgid="1210954576979621596">"Sebenzisa ngokuzenzakalelayo kule-accessory ye-USB"</string>
+    <!-- no translation found for usb_debugging_title (1114766024068112429) -->
+    <skip />
+    <!-- no translation found for usb_debugging_message (719863946976291180) -->
+    <skip />
+    <!-- no translation found for usb_debugging_always (4253099426793114693) -->
+    <skip />
     <string name="compat_mode_on" msgid="6623839244840638213">"Sondeza ukugcwalisa isikrini"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Nweba ukugcwalisa isikrini"</string>
     <string name="compat_mode_help_header" msgid="7969493989397529910">"Ukuhambelana Kokusondeza"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 9bbfc91..19b64ba 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -33,4 +33,5 @@
     <drawable name="system_bar_background">#ff000000</drawable>
     <!-- the darkening filter applied to notifications -->
     <drawable name="notification_icon_area_smoke">#aa000000</drawable>
+    <color name="notification_panel_scrim_color">#B0000000</color>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 8204e95..9539373 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -158,9 +158,10 @@
     <dimen name="notification_panel_margin_bottom">0dp</dimen>
     <dimen name="notification_panel_margin_left">0dp</dimen>
 
-    <!-- Gravity for the notification panel -->
+    <!-- Gravity for the notification & quick settings panels -->
     <!-- 0x37 = fill_horizontal|top -->
     <integer name="notification_panel_layout_gravity">0x37</integer>
+    <integer name="settings_panel_layout_gravity">0x37</integer>
 
     <!-- Height of the carrier/wifi name label -->
     <dimen name="carrier_label_height">24dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 2ce950f..5747f22 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -154,6 +154,15 @@
     <!-- Checkbox label for USB accessory dialogs.  [CHAR LIMIT=50] -->
     <string name="always_use_accessory">Use by default for this USB accessory</string>
 
+    <!-- Title of confirmation dialog for USB debugging -->
+    <string name="usb_debugging_title">Allow USB Debugging?</string>
+
+    <!-- Message of confirmation dialog for USB debugging -->
+    <string name="usb_debugging_message">Allow USB Debugging from this computer?\nYour RSA key fingerprint is\n<xliff:g id="fingerprint">%1$s</xliff:g></string>
+
+    <!-- Option to always allow USB debugging from the attached computer -->
+    <string name="usb_debugging_always">Always allow this computer</string>
+
     <!-- Checkbox label for application compatibility mode ON (zooming app to look like it's running
          on a phone).  [CHAR LIMIT=25] -->
     <string name="compat_mode_on">Zoom to fill screen</string>
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index a72074e..2512c02 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -74,10 +74,7 @@
         //noinspection PointlessBooleanExpression,ConstantConditions
         if (FIXED_SIZED_SURFACE && USE_OPENGL) {
             if (!isEmulator()) {
-                WindowManager windowManager =
-                        (WindowManager) getSystemService(Context.WINDOW_SERVICE);
-                Display display = windowManager.getDefaultDisplay();
-                mIsHwAccelerated = ActivityManager.isHighEndGfx(display);
+                mIsHwAccelerated = ActivityManager.isHighEndGfx();
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
index 475fb6d..281f25f 100644
--- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.os.UserHandle;
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.util.AttributeSet;
@@ -73,14 +74,16 @@
         // Close Recent Apps if needed
         mBar.animateCollapse(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL);
         // Launch Assist
-        Intent intent = SearchManager.getAssistIntent(mContext);
+        Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+                .getAssistIntent(mContext, UserHandle.USER_CURRENT);
         if (intent == null) return;
         try {
             ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
                     R.anim.search_launch_enter, R.anim.search_launch_exit,
                     getHandler(), this);
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            mContext.startActivity(intent, opts.toBundle());
+            mContext.startActivityAsUser(intent, opts.toBundle(),
+                    new UserHandle(UserHandle.USER_CURRENT));
         } catch (ActivityNotFoundException e) {
             Slog.w(TAG, "Activity not found for " + intent.getAction());
             onAnimationStarted();
@@ -140,7 +143,8 @@
     }
 
     private void maybeSwapSearchIcon() {
-        Intent intent = SearchManager.getAssistIntent(mContext);
+        Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+                .getAssistIntent(mContext, UserHandle.USER_CURRENT);
         if (intent != null) {
             ComponentName component = intent.getComponent();
             if (component == null || !mGlowPadView.replaceTargetDrawablesIfPresent(component,
@@ -277,6 +281,7 @@
     }
 
     public boolean isAssistantAvailable() {
-        return SearchManager.getAssistIntent(mContext) != null;
+        return ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+                .getAssistIntent(mContext, UserHandle.USER_CURRENT) != null;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index 0a57499..1bde949 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -31,6 +31,7 @@
 import android.os.ServiceManager;
 import android.util.Slog;
 import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
 
 public class SystemUIService extends Service {
     static final String TAG = "SystemUIService";
@@ -67,8 +68,7 @@
     @Override
     public void onCreate() {
         // Pick status bar or system bar.
-        IWindowManager wm = IWindowManager.Stub.asInterface(
-                ServiceManager.getService(Context.WINDOW_SERVICE));
+        IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
         try {
             SERVICES[0] = wm.hasSystemNavBar()
                     ? R.string.config_systemBarComponent
diff --git a/packages/SystemUI/src/com/android/systemui/UniverseBackground.java b/packages/SystemUI/src/com/android/systemui/UniverseBackground.java
index 4852a3e..7628754 100644
--- a/packages/SystemUI/src/com/android/systemui/UniverseBackground.java
+++ b/packages/SystemUI/src/com/android/systemui/UniverseBackground.java
@@ -33,6 +33,7 @@
 import android.view.View;
 import android.view.ViewRootImpl;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.view.animation.Transformation;
 import android.widget.FrameLayout;
 
@@ -96,7 +97,7 @@
     public UniverseBackground(Context context) {
         super(context);
         setBackgroundColor(0xff000000);
-        mSession = ViewRootImpl.getWindowSession(context.getMainLooper());
+        mSession = WindowManagerGlobal.getWindowSession(context.getMainLooper());
         mContent = View.inflate(context, R.layout.universe, null);
         addView(mContent);
         mContent.findViewById(R.id.close).setOnClickListener(new View.OnClickListener() {
@@ -155,7 +156,7 @@
         }
     }
 
-    public WindowManager.LayoutParams getLayoutParams(Display display) {
+    public WindowManager.LayoutParams getLayoutParams() {
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
                 WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND,
@@ -165,7 +166,7 @@
                     | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                 PixelFormat.OPAQUE);
         // this will allow the window to run in an overlay on devices that support this
-        if (ActivityManager.isHighEndGfx(display)) {
+        if (ActivityManager.isHighEndGfx()) {
             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         }
         lp.setTitle("UniverseBackground");
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 3e03f85..4d8c168 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -30,7 +30,7 @@
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Process;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.Log;
 
 import com.android.systemui.R;
@@ -245,7 +245,7 @@
 
                 final List<ActivityManager.RecentTaskInfo> recentTasks =
                         am.getRecentTasksForUser(MAX_TASKS,
-                                ActivityManager.RECENT_IGNORE_UNAVAILABLE, UserId.USER_CURRENT);
+                                ActivityManager.RECENT_IGNORE_UNAVAILABLE, UserHandle.USER_CURRENT);
                 int numTasks = recentTasks.size();
                 ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN)
                         .addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index bb647c3..b407078 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -36,7 +36,7 @@
 import android.net.Uri;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -49,6 +49,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
 import android.widget.AdapterView;
@@ -488,9 +489,7 @@
         mChoreo = new Choreographer(this, mRecentsScrim, mRecentsContainer, mRecentsNoApps, this);
 
         if (mRecentsScrim != null) {
-            Display d = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
-                .getDefaultDisplay();
-            mHighEndGfx = ActivityManager.isHighEndGfx(d);
+            mHighEndGfx = ActivityManager.isHighEndGfx();
             if (!mHighEndGfx) {
                 mRecentsScrim.setBackground(null);
             } else if (mRecentsScrim.getBackground() instanceof BitmapDrawable) {
@@ -733,8 +732,7 @@
         if (mTransitionBg == null) {
             mTransitionBg = (View) findViewById(R.id.recents_transition_background);
 
-            IWindowManager wm = IWindowManager.Stub.asInterface(
-                    ServiceManager.getService(Context.WINDOW_SERVICE));
+            IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
             try {
                 if (!wm.hasSystemNavBar()) {
                     FrameLayout.LayoutParams lp =
@@ -767,7 +765,7 @@
         show(false, true);
 
         mThumbnailScaleUpStarted = false;
-        ActivityOptions opts = ActivityOptions.makeDelayedThumbnailScaleUpAnimation(
+        ActivityOptions opts = ActivityOptions.makeThumbnailScaleUpAnimation(
                 holder.thumbnailViewImage, bm, 0, 0,
                 new ActivityOptions.OnAnimationStartedListener() {
                     @Override public void onAnimationStarted() {
@@ -790,7 +788,8 @@
                     | Intent.FLAG_ACTIVITY_TASK_ON_HOME
                     | Intent.FLAG_ACTIVITY_NEW_TASK);
             if (DEBUG) Log.v(TAG, "Starting activity " + intent);
-            context.startActivityAsUser(intent, opts.toBundle(), UserId.USER_CURRENT);
+            context.startActivityAsUser(intent, opts.toBundle(),
+                    new UserHandle(UserHandle.USER_CURRENT));
         }
         if (usingDrawingCache) {
             holder.thumbnailViewImage.setDrawingCacheEnabled(false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index ea5089d..e9e043e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -34,8 +34,10 @@
 import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.app.TaskStackBuilder;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.database.ContentObserver;
@@ -47,6 +49,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
@@ -58,13 +61,14 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowManagerGlobal;
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowManager;
-import android.view.WindowManagerImpl;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.PopupMenu;
 import android.widget.RemoteViews;
+import android.widget.TextView;
 
 import java.util.ArrayList;
 
@@ -72,6 +76,7 @@
     CommandQueue.Callbacks, RecentsPanelView.OnRecentsPanelVisibilityChangedListener {
     static final String TAG = "StatusBar";
     private static final boolean DEBUG = false;
+    public static final boolean MULTIUSER_DEBUG = false;
 
     protected static final int MSG_OPEN_RECENTS_PANEL = 1020;
     protected static final int MSG_CLOSE_RECENTS_PANEL = 1021;
@@ -112,6 +117,8 @@
 
     protected PopupMenu mNotificationBlamePopup;
 
+    protected int mCurrentUserId = 0;
+
     // UI-specific methods
 
     /**
@@ -120,18 +127,12 @@
      */
     protected abstract void createAndAddWindows();
 
+    protected WindowManager mWindowManager;
+    protected IWindowManager mWindowManagerService;
     protected Display mDisplay;
-    private IWindowManager mWindowManager;
+
     private boolean mDeviceProvisioned = false;
 
-    public IWindowManager getWindowManager() {
-        return mWindowManager;
-    }
-
-    public Display getDisplay() {
-        return mDisplay;
-    }
-
     public IStatusBarService getStatusBarService() {
         return mBarService;
     }
@@ -182,17 +183,15 @@
     };
 
     public void start() {
-        mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
-                .getDefaultDisplay();
+        mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+        mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
+        mDisplay = mWindowManager.getDefaultDisplay();
 
         mProvisioningObserver.onChange(false); // set up
         mContext.getContentResolver().registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.DEVICE_PROVISIONED), true,
                 mProvisioningObserver);
 
-        mWindowManager = IWindowManager.Stub.asInterface(
-                ServiceManager.getService(Context.WINDOW_SERVICE));
-
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
 
@@ -252,6 +251,40 @@
                    switches[3]
                    ));
         }
+
+        // XXX: this is currently broken and will always return 0, but should start working at some point
+        try {
+            mCurrentUserId = ActivityManagerNative.getDefault().getCurrentUser().id;
+        } catch (RemoteException e) {
+            Log.v(TAG, "Couldn't get current user ID; guessing it's 0", e);
+        }
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_USER_SWITCHED);
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                    mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+                    if (true) Slog.v(TAG, "userId " + mCurrentUserId + " is in the house");
+                    userSwitched(mCurrentUserId);
+                }
+            }}, filter);
+    }
+
+    public void userSwitched(int newUserId) {
+        // should be overridden
+    }
+
+    public boolean notificationIsForCurrentUser(StatusBarNotification n) {
+        final int thisUserId = mCurrentUserId;
+        final int notificationUserId = n.getUserId();
+        if (DEBUG && MULTIUSER_DEBUG) {
+            Slog.v(TAG, String.format("%s: current userid: %d, notification userid: %d",
+                    n, thisUserId, notificationUserId));
+        }
+        return thisUserId == notificationUserId;
     }
 
     protected View updateNotificationVetoButton(View row, StatusBarNotification n) {
@@ -395,7 +428,7 @@
         boolean firstScreenful = false;
         if (mRecentsPanel != null) {
             visible = mRecentsPanel.isShowing();
-            WindowManagerImpl.getDefault().removeView(mRecentsPanel);
+            mWindowManager.removeView(mRecentsPanel);
             if (visible) {
                 recentTasksList = mRecentsPanel.getRecentTasksList();
                 firstScreenful = mRecentsPanel.getFirstScreenful();
@@ -415,7 +448,7 @@
 
         WindowManager.LayoutParams lp = getRecentsLayoutParams(mRecentsPanel.getLayoutParams());
 
-        WindowManagerImpl.getDefault().addView(mRecentsPanel, lp);
+        mWindowManager.addView(mRecentsPanel, lp);
         mRecentsPanel.setBar(this);
         if (visible) {
             mRecentsPanel.show(true, false, recentTasksList, firstScreenful);
@@ -428,7 +461,7 @@
         boolean visible = false;
         if (mSearchPanelView != null) {
             visible = mSearchPanelView.isShowing();
-            WindowManagerImpl.getDefault().removeView(mSearchPanelView);
+            mWindowManager.removeView(mSearchPanelView);
         }
 
         // Provide SearchPanel with a temporary parent to allow layout params to work.
@@ -441,7 +474,7 @@
 
         WindowManager.LayoutParams lp = getSearchLayoutParams(mSearchPanelView.getLayoutParams());
 
-        WindowManagerImpl.getDefault().addView(mSearchPanelView, lp);
+        mWindowManager.addView(mSearchPanelView, lp);
         mSearchPanelView.setBar(this);
         if (visible) {
             mSearchPanelView.show(true, false);
@@ -604,6 +637,14 @@
         applyLegacyRowBackground(sbn, content);
 
         row.setTag(R.id.expandable_tag, Boolean.valueOf(large != null));
+
+        if (MULTIUSER_DEBUG) {
+            TextView debug = (TextView) row.findViewById(R.id.debug_info);
+            if (debug != null) {
+                debug.setVisibility(View.VISIBLE);
+                debug.setText("U " + entry.notification.getUserId());
+            }
+        }
         entry.row = row;
         entry.content = content;
         entry.expanded = expandedOneU;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
index 81a16ae..0f894a1 100755
--- a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java
@@ -101,8 +101,7 @@
                 mDownTime = ev.getDownTime();
             } else {
                 if (mDownTime != ev.getDownTime()) {
-                    // TODO: remove
-                    throw new RuntimeException("Assertion failure in GestureRecorder: event downTime ("
+                    Slog.w(TAG, "Assertion failure in GestureRecorder: event downTime ("
                             +ev.getDownTime()+") does not match gesture downTime ("+mDownTime+")");
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 63c9b79..33973b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -18,13 +18,11 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
 import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Message;
@@ -34,19 +32,14 @@
 import android.view.animation.AccelerateInterpolator;
 import android.view.Display;
 import android.view.MotionEvent;
-import android.view.VelocityTracker;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.Surface;
-import android.view.Window;
 import android.view.WindowManager;
-import android.view.WindowManagerImpl;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.lang.StringBuilder;
 
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.R;
@@ -244,7 +237,8 @@
             } else {
                 return;
             }
-            WindowManagerImpl.getDefault().updateViewLayout(this, lp);
+            WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
+            wm.updateViewLayout(this, lp);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
new file mode 100644
index 0000000..13a34ad
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+public class NotificationPanelView extends PanelView {
+    public NotificationPanelView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void fling(float vel, boolean always) {
+        ((PhoneStatusBarView) mBar).mBar.getGestureRecorder().tag(
+            "fling " + ((vel > 0) ? "open" : "closed"),
+            "notifications,v=" + vel);
+        super.fling(vel, always);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
new file mode 100644
index 0000000..bffb903
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -0,0 +1,158 @@
+package com.android.systemui.statusbar.phone;
+
+import java.util.ArrayList;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
+
+public class PanelBar extends FrameLayout {
+    public static final boolean DEBUG = false;
+    public static final String TAG = PanelView.class.getSimpleName();
+    public static final void LOG(String fmt, Object... args) {
+        if (!DEBUG) return;
+        Slog.v(TAG, String.format(fmt, args));
+    }
+
+    private PanelHolder mPanelHolder;
+    private ArrayList<PanelView> mPanels = new ArrayList<PanelView>();
+    protected PanelView mTouchingPanel;
+    private static final int STATE_CLOSED = 0;
+    private static final int STATE_TRANSITIONING = 1;
+    private static final int STATE_OPEN = 2;
+    private int mState = STATE_CLOSED;
+    private boolean mTracking;
+
+    private void go(int state) {
+        LOG("go state: %d -> %d", mState, state);
+        mState = state;
+    }
+
+    public PanelBar(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+    }
+
+    public void addPanel(PanelView pv) {
+        mPanels.add(pv);
+        pv.setBar(this);
+    }
+
+    public void setPanelHolder(PanelHolder ph) {
+        if (ph == null) {
+            Slog.e(TAG, "setPanelHolder: null PanelHolder", new Throwable());
+            return;
+        }
+        ph.setBar(this);
+        mPanelHolder = ph;
+        final int N = ph.getChildCount();
+        for (int i=0; i<N; i++) {
+            final PanelView v = (PanelView) ph.getChildAt(i);
+            if (v != null) {
+                addPanel(v);
+            }
+        }
+    }
+
+    public float getBarHeight() {
+        return getMeasuredHeight();
+    }
+
+    public PanelView selectPanelForTouchX(float x) {
+        final int N = mPanels.size();
+        return mPanels.get((int)(N * x / getMeasuredWidth()));
+    }
+
+    public boolean panelsEnabled() {
+        return true;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        // Allow subclasses to implement enable/disable semantics
+        if (!panelsEnabled()) return false;
+
+        // figure out which panel needs to be talked to here
+        if (event.getAction() == MotionEvent.ACTION_DOWN) {
+            mTouchingPanel = selectPanelForTouchX(event.getX());
+            mPanelHolder.setSelectedPanel(mTouchingPanel);
+            LOG("PanelBar.onTouch: state=%d ACTION_DOWN: panel %s", mState, mTouchingPanel.getName());
+            if (mState == STATE_CLOSED || mState == STATE_OPEN) {
+                go(STATE_TRANSITIONING);
+                onPanelPeeked();
+            }
+        }
+        final boolean result = mTouchingPanel.getHandle().dispatchTouchEvent(event);
+        return result;
+    }
+
+    public void panelExpansionChanged(PanelView panel, float frac) {
+        boolean fullyClosed = true;
+        PanelView fullyOpenedPanel = null;
+        LOG("panelExpansionChanged: start state=%d panel=%s", mState, panel.getName());
+        for (PanelView pv : mPanels) {
+            // adjust any other panels that may be partially visible
+            if (pv.getExpandedHeight() > 0f) {
+                fullyClosed = false;
+                final float thisFrac = pv.getExpandedFraction();
+                LOG("panelExpansionChanged:  -> %s: f=%.1f", pv.getName(), thisFrac);
+                if (panel == pv) {
+                    if (thisFrac == 1f) fullyOpenedPanel = panel;
+                } else {
+                    pv.setExpandedFraction(1f-frac);
+                }
+            }
+        }
+        if (fullyOpenedPanel != null && !mTracking) {
+            go(STATE_OPEN);
+            onPanelFullyOpened(fullyOpenedPanel);
+        } else if (fullyClosed && !mTracking) {
+            go(STATE_CLOSED);
+            onAllPanelsCollapsed();
+        }
+
+        LOG("panelExpansionChanged: end state=%d [%s%s ]", mState,
+                (fullyOpenedPanel!=null)?" fullyOpened":"", fullyClosed?" fullyClosed":"");
+    }
+
+    public void collapseAllPanels(boolean animate) {
+        for (PanelView pv : mPanels) {
+            if (animate && pv == mTouchingPanel) {
+                mTouchingPanel.collapse();
+            } else {
+                pv.setExpandedFraction(0); // just in case
+            }
+        }
+    }
+
+    public void onPanelPeeked() {
+        LOG("onPanelPeeked");
+    }
+
+    public void onAllPanelsCollapsed() {
+        LOG("onAllPanelsCollapsed");
+    }
+
+    public void onPanelFullyOpened(PanelView openPanel) {
+        LOG("onPanelFullyOpened");
+    }
+
+    public void onTrackingStarted(PanelView panel) {
+        mTracking = true;
+        if (panel != mTouchingPanel) {
+            LOG("shouldn't happen: onTrackingStarted(%s) != mTouchingPanel(%s)",
+                    panel, mTouchingPanel);
+        }
+    }
+
+    public void onTrackingStopped(PanelView panel) {
+        mTracking = false;
+        panelExpansionChanged(panel, panel.getExpandedFraction());
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java
new file mode 100644
index 0000000..abd82bd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java
@@ -0,0 +1,65 @@
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
+
+public class PanelHolder extends FrameLayout {
+
+    private int mSelectedPanelIndex;
+    private PanelBar mBar;
+
+    public PanelHolder(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setChildrenDrawingOrderEnabled(true);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        setChildrenDrawingOrderEnabled(true);
+    }
+
+    public int getPanelIndex(PanelView pv) {
+        final int N = getChildCount();
+        for (int i=0; i<N; i++) {
+            final PanelView v = (PanelView) getChildAt(i);
+            if (pv == v) return i;
+        }
+        return -1;
+    }
+
+    public void setSelectedPanel(PanelView pv) {
+        mSelectedPanelIndex = getPanelIndex(pv);
+    }
+
+    @Override
+    protected int getChildDrawingOrder(int childCount, int i) {
+        if (mSelectedPanelIndex == -1) {
+            return i;
+        } else {
+            if (i == childCount - 1) {
+                return mSelectedPanelIndex;
+            } else if (i >= mSelectedPanelIndex) {
+                return i + 1;
+            } else {
+                return i;
+            }
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                mBar.collapseAllPanels(true);
+                break;
+        }
+        return false;
+    }
+
+    public void setBar(PanelBar panelBar) {
+        mBar = panelBar;
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
new file mode 100644
index 0000000..33f467f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -0,0 +1,365 @@
+package com.android.systemui.statusbar.phone;
+
+import android.animation.TimeAnimator;
+import android.animation.TimeAnimator.TimeListener;
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.systemui.R;
+
+public class PanelView extends FrameLayout {
+    public static final boolean DEBUG = false;
+    public static final String TAG = PanelView.class.getSimpleName();
+    public final void LOG(String fmt, Object... args) {
+        if (!DEBUG) return;
+        Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
+    }
+
+    public static final boolean BRAKES = false;
+    private static final boolean STRETCH_PAST_CONTENTS = true;
+
+    private float mSelfExpandVelocityPx; // classic value: 2000px/s
+    private float mSelfCollapseVelocityPx; // classic value: 2000px/s (will be negated to collapse "up")
+    private float mFlingExpandMinVelocityPx; // classic value: 200px/s
+    private float mFlingCollapseMinVelocityPx; // classic value: 200px/s
+    private float mCollapseMinDisplayFraction; // classic value: 0.08 (25px/min(320px,480px) on G1)
+    private float mExpandMinDisplayFraction; // classic value: 0.5 (drag open halfway to expand)
+    private float mFlingGestureMaxXVelocityPx; // classic value: 150px/s
+
+    private float mExpandAccelPx; // classic value: 2000px/s/s
+    private float mCollapseAccelPx; // classic value: 2000px/s/s (will be negated to collapse "up")
+
+    private float mFlingGestureMaxOutputVelocityPx; // how fast can it really go? (should be a little
+                                                    // faster than mSelfCollapseVelocityPx)
+
+    private float mCollapseBrakingDistancePx = 200; // XXX Resource
+    private float mExpandBrakingDistancePx = 150; // XXX Resource
+    private float mBrakingSpeedPx = 150; // XXX Resource
+
+    private View mHandleView;
+    private float mTouchOffset;
+    private float mExpandedFraction = 0;
+    private float mExpandedHeight = 0;
+    private boolean mClosing;
+    private boolean mRubberbanding;
+    private boolean mTracking;
+
+    private TimeAnimator mTimeAnimator;
+    private VelocityTracker mVelocityTracker;
+
+    private int[] mAbsPos = new int[2];
+    PanelBar mBar;
+
+    private final TimeListener mAnimationCallback = new TimeListener() {
+        @Override
+        public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
+            animationTick(deltaTime);
+        }
+    };
+
+    private final Runnable mStopAnimator = new Runnable() { public void run() {
+        if (mTimeAnimator.isStarted()) {
+            mTimeAnimator.end();
+            mRubberbanding = false;
+        }
+    }};
+
+    private float mVel, mAccel;
+    private int mFullHeight = 0;
+    private String mViewName;
+
+    private void animationTick(long dtms) {
+        if (!mTimeAnimator.isStarted()) {
+            // XXX HAX to work around bug in TimeAnimator.end() not resetting its last time
+            mTimeAnimator = new TimeAnimator();
+            mTimeAnimator.setTimeListener(mAnimationCallback);
+
+            mTimeAnimator.start();
+            
+            mRubberbanding = STRETCH_PAST_CONTENTS && mExpandedHeight > getFullHeight();
+            mClosing = (mExpandedHeight > 0 && mVel < 0) || mRubberbanding;
+        } else if (dtms > 0) {
+            final float dt = dtms * 0.001f;                  // ms -> s
+            LOG("tick: v=%.2fpx/s dt=%.4fs", mVel, dt);
+            LOG("tick: before: h=%d", (int) mExpandedHeight);
+
+            final float fh = getFullHeight();
+            boolean braking = false;
+            if (BRAKES) {
+                if (mClosing) {
+                    braking = mExpandedHeight <= mCollapseBrakingDistancePx;
+                    mAccel = braking ? 10*mCollapseAccelPx : -mCollapseAccelPx;
+                } else {
+                    braking = mExpandedHeight >= (fh-mExpandBrakingDistancePx);
+                    mAccel = braking ? 10*-mExpandAccelPx : mExpandAccelPx;
+                }
+            } else {
+                mAccel = mClosing ? -mCollapseAccelPx : mExpandAccelPx;
+            }
+
+            mVel += mAccel * dt;
+
+            if (braking) {
+                if (mClosing && mVel > -mBrakingSpeedPx) {
+                    mVel = -mBrakingSpeedPx;
+                } else if (!mClosing && mVel < mBrakingSpeedPx) {
+                    mVel = mBrakingSpeedPx;
+                }
+            } else {
+                if (mClosing && mVel > -mFlingCollapseMinVelocityPx) {
+                    mVel = -mFlingCollapseMinVelocityPx;
+                } else if (!mClosing && mVel > mFlingGestureMaxOutputVelocityPx) {
+                    mVel = mFlingGestureMaxOutputVelocityPx;
+                }
+            }
+
+            float h = mExpandedHeight + mVel * dt;
+            
+            if (mRubberbanding && h < fh) {
+                h = fh;
+            }
+
+            LOG("tick: new h=%d closing=%s", (int) h, mClosing?"true":"false");
+
+            setExpandedHeightInternal(h);
+
+            mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
+
+            if (mVel == 0
+                    || (mClosing && mExpandedHeight == 0)
+                    || ((mRubberbanding || !mClosing) && mExpandedHeight == fh)) {
+                post(mStopAnimator);
+            }
+        }
+    }
+
+    public PanelView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mTimeAnimator = new TimeAnimator();
+        mTimeAnimator.setTimeListener(mAnimationCallback);
+    }
+
+    private void loadDimens() {
+        final Resources res = getContext().getResources();
+
+        mSelfExpandVelocityPx = res.getDimension(R.dimen.self_expand_velocity);
+        mSelfCollapseVelocityPx = res.getDimension(R.dimen.self_collapse_velocity);
+        mFlingExpandMinVelocityPx = res.getDimension(R.dimen.fling_expand_min_velocity);
+        mFlingCollapseMinVelocityPx = res.getDimension(R.dimen.fling_collapse_min_velocity);
+
+        mCollapseMinDisplayFraction = res.getFraction(R.dimen.collapse_min_display_fraction, 1, 1);
+        mExpandMinDisplayFraction = res.getFraction(R.dimen.expand_min_display_fraction, 1, 1);
+
+        mExpandAccelPx = res.getDimension(R.dimen.expand_accel);
+        mCollapseAccelPx = res.getDimension(R.dimen.collapse_accel);
+
+        mFlingGestureMaxXVelocityPx = res.getDimension(R.dimen.fling_gesture_max_x_velocity);
+
+        mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity);
+    }
+
+    private void trackMovement(MotionEvent event) {
+        // Add movement to velocity tracker using raw screen X and Y coordinates instead
+        // of window coordinates because the window frame may be moving at the same time.
+        float deltaX = event.getRawX() - event.getX();
+        float deltaY = event.getRawY() - event.getY();
+        event.offsetLocation(deltaX, deltaY);
+        mVelocityTracker.addMovement(event);
+        event.offsetLocation(-deltaX, -deltaY);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        loadDimens();
+
+        mHandleView = findViewById(R.id.handle);
+        LOG("handle view: " + mHandleView);
+        if (mHandleView != null) {
+            mHandleView.setOnTouchListener(new View.OnTouchListener() {
+                @Override
+                public boolean onTouch(View v, MotionEvent event) {
+                    final float y = event.getY();
+                    final float rawY = event.getRawY();
+                    LOG("handle.onTouch: a=%s y=%.1f rawY=%.1f off=%.1f",
+                            MotionEvent.actionToString(event.getAction()),
+                            y, rawY, mTouchOffset);
+                    PanelView.this.getLocationOnScreen(mAbsPos);
+
+                    switch (event.getAction()) {
+                        case MotionEvent.ACTION_DOWN:
+                            mTracking = true;
+                            mVelocityTracker = VelocityTracker.obtain();
+                            trackMovement(event);
+                            mBar.onTrackingStarted(PanelView.this);
+                            mTouchOffset = (rawY - mAbsPos[1]) - PanelView.this.getExpandedHeight();
+                            break;
+
+                        case MotionEvent.ACTION_MOVE:
+                            PanelView.this.setExpandedHeightInternal(rawY - mAbsPos[1] - mTouchOffset);
+
+                            mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
+
+                            trackMovement(event);
+                            break;
+
+                        case MotionEvent.ACTION_UP:
+                        case MotionEvent.ACTION_CANCEL:
+                            mTracking = false;
+                            mBar.onTrackingStopped(PanelView.this);
+                            trackMovement(event);
+                            mVelocityTracker.computeCurrentVelocity(1000);
+
+                            float yVel = mVelocityTracker.getYVelocity();
+                            boolean negative = yVel < 0;
+
+                            float xVel = mVelocityTracker.getXVelocity();
+                            if (xVel < 0) {
+                                xVel = -xVel;
+                            }
+                            if (xVel > mFlingGestureMaxXVelocityPx) {
+                                xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
+                            }
+
+                            float vel = (float)Math.hypot(yVel, xVel);
+                            if (vel > mFlingGestureMaxOutputVelocityPx) {
+                                vel = mFlingGestureMaxOutputVelocityPx;
+                            }
+                            if (negative) {
+                                vel = -vel;
+                            }
+
+                            LOG("gesture: vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f",
+                                    mVelocityTracker.getXVelocity(),
+                                    mVelocityTracker.getYVelocity(),
+                                    xVel, yVel,
+                                    vel);
+
+                            fling(vel, true);
+
+                            mVelocityTracker.recycle();
+                            mVelocityTracker = null;
+
+                            break;
+                    }
+                    return true;
+                }});
+        }
+    }
+
+    public void fling(float vel, boolean always) {
+        mVel = vel;
+
+        if (always||mVel != 0) {
+            animationTick(0); // begin the animation
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mViewName = getResources().getResourceName(getId());
+    }
+
+    public String getName() {
+        return mViewName;
+    }
+
+    @Override
+    protected void onViewAdded(View child) {
+        LOG("onViewAdded: " + child);
+    }
+
+    public View getHandle() {
+        return mHandleView;
+    }
+
+    // Rubberbands the panel to hold its contents.
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        LOG("onMeasure(%d, %d) -> (%d, %d)",
+                widthMeasureSpec, heightMeasureSpec, getMeasuredWidth(), getMeasuredHeight());
+        mFullHeight = getMeasuredHeight();
+        // if one of our children is getting smaller, we should track that
+        if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted() && mExpandedHeight > 0 && mExpandedHeight != mFullHeight) {
+            mExpandedHeight = mFullHeight;
+        }
+        heightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                    (int) mExpandedHeight, MeasureSpec.AT_MOST); // MeasureSpec.getMode(heightMeasureSpec));
+        setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
+    }
+
+
+    public void setExpandedHeight(float height) {
+        post(mStopAnimator);
+        setExpandedHeightInternal(height);
+    }
+
+    @Override
+    protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
+        LOG("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom, (int)mExpandedHeight, (int)mFullHeight);
+        super.onLayout(changed, left, top, right, bottom);
+    }
+
+    public void setExpandedHeightInternal(float h) {
+        float fh = getFullHeight();
+        if (fh == 0) {
+            // Hmm, full height hasn't been computed yet
+        }
+
+        LOG("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh, mTracking?"T":"f", mRubberbanding?"T":"f");
+
+        if (h < 0) h = 0;
+        if (!(STRETCH_PAST_CONTENTS && (mTracking || mRubberbanding)) && h > fh) h = fh;
+        mExpandedHeight = h;
+
+        requestLayout();
+//        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+//        lp.height = (int) mExpandedHeight;
+//        setLayoutParams(lp);
+
+        mExpandedFraction = Math.min(1f, h / fh);
+    }
+
+    private float getFullHeight() {
+        return mFullHeight;
+    }
+
+    public void setExpandedFraction(float frac) {
+        setExpandedHeight(getFullHeight() * frac);
+    }
+
+    public float getExpandedHeight() {
+        return mExpandedHeight;
+    }
+
+    public float getExpandedFraction() {
+        return mExpandedFraction;
+    }
+
+    public void setBar(PanelBar panelBar) {
+        mBar = panelBar;
+    }
+
+    public void collapse() {
+        // TODO: abort animation or ongoing touch
+        if (mExpandedHeight > 0) {
+            fling(-mSelfCollapseVelocityPx, /*always=*/ true);
+        }
+    }
+
+    public void expand() {
+        if (mExpandedHeight < getFullHeight()) {
+            fling (mSelfExpandVelocityPx, /*always=*/ true);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 0ccc415..2886441 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -46,13 +46,12 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.dreams.IDreamManager;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
-import android.view.Choreographer;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.IWindowManager;
@@ -61,9 +60,9 @@
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowManagerGlobal;
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowManager;
-import android.view.WindowManagerImpl;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -77,7 +76,6 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarNotification;
 import com.android.systemui.R;
-import com.android.systemui.UniverseBackground;
 import com.android.systemui.recent.RecentTasksLoader;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
@@ -111,8 +109,7 @@
     public static final String ACTION_STATUSBAR_START
             = "com.android.internal.policy.statusbar.START";
 
-    private static final boolean DIM_BEHIND_EXPANDED_PANEL = true;
-    private static final boolean SHOW_CARRIER_LABEL = true;
+    private static final boolean SHOW_CARRIER_LABEL = false; // XXX: doesn't work with rubberband panels right now
 
     private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
     private static final int MSG_CLOSE_NOTIFICATION_PANEL = 1001;
@@ -153,14 +150,11 @@
     int mIconHPadding = -1;
     Display mDisplay;
 
-    IWindowManager mWindowManager;
     IDreamManager mDreamManager;
 
     StatusBarWindowView mStatusBarWindow;
     PhoneStatusBarView mStatusBarView;
 
-    UniverseBackground mUniverseBackground;
-
     int mPixelFormat;
     Object mQueueLock = new Object();
 
@@ -171,14 +165,19 @@
     LinearLayout mStatusIcons;
 
     // expanded notifications
-    View mNotificationPanel; // the sliding/resizing panel within the notification window
+    PanelView mNotificationPanel; // the sliding/resizing panel within the notification window
     ScrollView mScrollView;
     View mExpandedContents;
-    int mNotificationPanelMarginBottomPx, mNotificationPanelMarginLeftPx;
     final Rect mNotificationPanelBackgroundPadding = new Rect();
     int mNotificationPanelGravity;
+    int mNotificationPanelMarginBottomPx, mNotificationPanelMarginPx;
     int mNotificationPanelMinHeight;
     boolean mNotificationPanelIsFullScreenWidth;
+    TextView mNotificationPanelDebugText;
+
+    // settings
+    PanelView mSettingsPanel;
+    int mSettingsPanelGravity;
 
     // top bar
     View mClearButton;
@@ -191,13 +190,8 @@
     private int mCarrierLabelHeight;
     private TextView mEmergencyCallLabel;
 
-    // drag bar
-    CloseDragHandle mCloseView;
-    private int mCloseViewHeight;
-
     // position
     int[] mPositionTmp = new int[2];
-    boolean mExpanded;
     boolean mExpandedVisible;
 
     // the date view
@@ -222,7 +216,6 @@
     boolean mTracking;
     VelocityTracker mVelocityTracker;
 
-    Choreographer mChoreographer;
     boolean mAnimating;
     boolean mClosing; // only valid when mAnimating; indicates the initial acceleration
     float mAnimY;
@@ -262,48 +255,11 @@
         }
     };
 
-    private final Runnable mStartRevealAnimation = new Runnable() {
-        @Override
-        public void run() {
-            mAnimAccel = mExpandAccelPx;
-            mAnimVel = mFlingExpandMinVelocityPx;
-            mAnimY = getStatusBarHeight();
-            updateExpandedViewPos((int)mAnimY);
-
-            mAnimating = true;
-            mAnimatingReveal = true;
-            resetLastAnimTime();
-            mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
-                mAnimationCallback, null);
-            mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
-                mRevealAnimationCallback, null);
-            mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION,
-                mRevealAnimationCallback, null);
-        }
-    };
-
-    private final Runnable mPerformSelfExpandFling = new Runnable() {
-        @Override
-        public void run() {
-            performFling(0, mSelfExpandVelocityPx, true);
-        }
-    };
-
-    private final Runnable mPerformFling = new Runnable() {
-        @Override
-        public void run() {
-            performFling(mFlingY + mViewDelta, mFlingVelocity, false);
-        }
-    };
-
     @Override
     public void start() {
         mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
                 .getDefaultDisplay();
 
-        mWindowManager = IWindowManager.Stub.asInterface(
-                ServiceManager.getService(Context.WINDOW_SERVICE));
-
         mDreamManager = IDreamManager.Stub.asInterface(
                 ServiceManager.checkService("dreams"));
 
@@ -313,11 +269,6 @@
 
         if (ENABLE_INTRUDERS) addIntruderView();
 
-        mUniverseBackground = new UniverseBackground(mContext);
-        mUniverseBackground.setVisibility(View.GONE);
-        WindowManagerImpl.getDefault().addView(mUniverseBackground,
-                mUniverseBackground.getLayoutParams(mDisplay));
-
         // Lastly, call to the icon policy to install/update all the icons.
         mIconPolicy = new PhoneStatusBarPolicy(mContext);
     }
@@ -345,7 +296,7 @@
             @Override
             public boolean onTouch(View v, MotionEvent event) {
                 if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                    if (mExpanded && !mAnimating) {
+                    if (mExpandedVisible && !mAnimating) {
                         animateCollapse();
                     }
                 }
@@ -353,39 +304,51 @@
             }});
 
         mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
-        mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
+        mStatusBarView.setBar(this);
+
+        PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
+        mStatusBarView.setPanelHolder(holder);
+
+        mNotificationPanel = (PanelView) mStatusBarWindow.findViewById(R.id.notification_panel);
         // don't allow clicks on the panel to pass through to the background where they will cause the panel to close
-        mNotificationPanel.setOnTouchListener(new View.OnTouchListener() {
+        View.OnTouchListener clickStopper = new View.OnTouchListener() {
             @Override
             public boolean onTouch(View v, MotionEvent event) {
                 return true;
             }
-        });
+        };
+        mNotificationPanel.setOnTouchListener(clickStopper);
         mNotificationPanelIsFullScreenWidth =
             (mNotificationPanel.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT);
         mNotificationPanel.setSystemUiVisibility(
                   View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER
                 | (mNotificationPanelIsFullScreenWidth ? 0 : View.STATUS_BAR_DISABLE_SYSTEM_INFO));
 
-        if (!ActivityManager.isHighEndGfx(mDisplay)) {
+        // quick settings (WIP)
+        mSettingsPanel = (PanelView) mStatusBarWindow.findViewById(R.id.settings_panel);
+        mSettingsPanel.setOnTouchListener(clickStopper);
+
+        if (!ActivityManager.isHighEndGfx()) {
             mStatusBarWindow.setBackground(null);
             mNotificationPanel.setBackground(new FastColorDrawable(context.getResources().getColor(
                     R.color.notification_panel_solid_background)));
+            mSettingsPanel.setBackground(new FastColorDrawable(context.getResources().getColor(
+                    R.color.notification_panel_solid_background)));
         }
         if (ENABLE_INTRUDERS) {
             mIntruderAlertView = (IntruderAlertView) View.inflate(context, R.layout.intruder_alert, null);
             mIntruderAlertView.setVisibility(View.GONE);
             mIntruderAlertView.setBar(this);
         }
+        if (MULTIUSER_DEBUG) {
+            mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(R.id.header_debug_info);
+            mNotificationPanelDebugText.setVisibility(View.VISIBLE);
+        }
 
         updateShowSearchHoldoff();
 
-        mStatusBarView.mService = this;
-
-        mChoreographer = Choreographer.getInstance();
-
         try {
-            boolean showNav = mWindowManager.hasNavigationBar();
+            boolean showNav = mWindowManagerService.hasNavigationBar();
             if (DEBUG) Slog.v(TAG, "hasNavigationBar=" + showNav);
             if (showNav) {
                 mNavigationBarView =
@@ -429,10 +392,6 @@
         TickerView tickerView = (TickerView)mStatusBarView.findViewById(R.id.tickerText);
         tickerView.mTicker = mTicker;
 
-        mCloseView = (CloseDragHandle)mStatusBarWindow.findViewById(R.id.close);
-        mCloseView.mService = this;
-        mCloseViewHeight = res.getDimensionPixelSize(R.dimen.close_handle_height);
-
         mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
 
         // set the inital view visibility
@@ -511,7 +470,7 @@
                 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
-        if (ActivityManager.isHighEndGfx(mDisplay)) {
+        if (ActivityManager.isHighEndGfx()) {
             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         } else {
             lp.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
@@ -536,7 +495,7 @@
                 | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
-        if (ActivityManager.isHighEndGfx(mDisplay)) {
+        if (ActivityManager.isHighEndGfx()) {
             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         }
         lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
@@ -572,7 +531,7 @@
         WindowManager.LayoutParams lp =
             (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
         lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-        WindowManagerImpl.getDefault().updateViewLayout(mNavigationBarView, lp);
+        mWindowManager.updateViewLayout(mNavigationBarView, lp);
     }
 
     @Override
@@ -581,7 +540,7 @@
         WindowManager.LayoutParams lp =
             (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
         lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-        WindowManagerImpl.getDefault().updateViewLayout(mNavigationBarView, lp);
+        mWindowManager.updateViewLayout(mNavigationBarView, lp);
     }
 
     protected int getStatusBarGravity() {
@@ -597,10 +556,6 @@
         return mNaturalBarHeight;
     }
 
-    private int getCloseViewHeight() {
-        return mCloseViewHeight;
-    }
-
     private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
         public void onClick(View v) {
             toggleRecentApps();
@@ -661,8 +616,7 @@
 
         prepareNavigationBarView();
 
-        WindowManagerImpl.getDefault().addView(
-                mNavigationBarView, getNavigationBarLayoutParams());
+        mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
     }
 
     private void repositionNavigationBar() {
@@ -670,8 +624,7 @@
 
         prepareNavigationBarView();
 
-        WindowManagerImpl.getDefault().updateViewLayout(
-                mNavigationBarView, getNavigationBarLayoutParams());
+        mWindowManager.updateViewLayout(mNavigationBarView, getNavigationBarLayoutParams());
     }
 
     private WindowManager.LayoutParams getNavigationBarLayoutParams() {
@@ -685,7 +638,7 @@
                     | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                 PixelFormat.OPAQUE);
         // this will allow the navbar to run in an overlay on devices that support this
-        if (ActivityManager.isHighEndGfx(mDisplay)) {
+        if (ActivityManager.isHighEndGfx()) {
             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         }
 
@@ -712,7 +665,7 @@
         lp.packageName = mContext.getPackageName();
         lp.windowAnimations = R.style.Animation_StatusBar_IntruderAlert;
 
-        WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp);
+        mWindowManager.addView(mIntruderAlertView, lp);
     }
 
     public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
@@ -852,9 +805,9 @@
         // If the device hasn't been through Setup, we only show system notifications
         for (int i=0; i<N; i++) {
             Entry ent = mNotificationData.get(N-i-1);
-            if (provisioned || showNotificationEvenIfUnprovisioned(ent.notification)) {
-                toShow.add(ent.row);
-            }
+            if (!(provisioned || showNotificationEvenIfUnprovisioned(ent.notification))) continue;
+            if (!notificationIsForCurrentUser(ent.notification)) continue;
+            toShow.add(ent.row);
         }
 
         ArrayList<View> toRemove = new ArrayList<View>();
@@ -900,10 +853,10 @@
         // If the device hasn't been through Setup, we only show system notifications
         for (int i=0; i<N; i++) {
             Entry ent = mNotificationData.get(N-i-1);
-            if ((provisioned && ent.notification.score >= HIDE_ICONS_BELOW_SCORE)
-                    || showNotificationEvenIfUnprovisioned(ent.notification)) {
-                toShow.add(ent.icon);
-            }
+            if (!((provisioned && ent.notification.score >= HIDE_ICONS_BELOW_SCORE)
+                    || showNotificationEvenIfUnprovisioned(ent.notification))) continue;
+            if (!notificationIsForCurrentUser(ent.notification)) continue;
+            toShow.add(ent.icon);
         }
 
         ArrayList<View> toRemove = new ArrayList<View>();
@@ -1169,20 +1122,6 @@
         }
     }
 
-    final Runnable mAnimationCallback = new Runnable() {
-        @Override
-        public void run() {
-            doAnimation(mChoreographer.getFrameTimeNanos());
-        }
-    };
-
-    final Runnable mRevealAnimationCallback = new Runnable() {
-        @Override
-        public void run() {
-            doRevealAnimation(mChoreographer.getFrameTimeNanos());
-        }
-    };
-
     View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
         public void onFocusChange(View v, boolean hasFocus) {
             // Because 'v' is a ViewGroup, all its children will be (un)selected
@@ -1191,7 +1130,7 @@
         }
     };
 
-    private void makeExpandedVisible(boolean revealAfterDraw) {
+    void makeExpandedVisible(boolean revealAfterDraw) {
         if (SPEW) Slog.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
         if (mExpandedVisible) {
             return;
@@ -1212,44 +1151,25 @@
         lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
         lp.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
         lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
-        final WindowManager wm = WindowManagerImpl.getDefault();
-        wm.updateViewLayout(mStatusBarWindow, lp);
+        mWindowManager.updateViewLayout(mStatusBarWindow, lp);
 
         // Updating the window layout will force an expensive traversal/redraw.
         // Kick off the reveal animation after this is complete to avoid animation latency.
         if (revealAfterDraw) {
-            mHandler.post(mStartRevealAnimation);
+//            mHandler.post(mStartRevealAnimation);
         }
 
         visibilityChanged(true);
     }
 
-    public void animateExpand() {
-        if (SPEW) Slog.d(TAG, "Animate expand: expanded=" + mExpanded);
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return ;
-        }
-        if (mExpanded) {
-            return;
-        }
-
-        prepareTracking(0, true);
-        mHandler.post(mPerformSelfExpandFling);
-    }
-
     public void animateCollapse() {
         animateCollapse(CommandQueue.FLAG_EXCLUDE_NONE);
     }
 
     public void animateCollapse(int flags) {
-        animateCollapse(flags, 1.0f);
-    }
-
-    public void animateCollapse(int flags, float velocityMultiplier) {
         if (SPEW) {
-            Slog.d(TAG, "animateCollapse(): mExpanded=" + mExpanded
+            Slog.d(TAG, "animateCollapse(): "
                     + " mExpandedVisible=" + mExpandedVisible
-                    + " mExpanded=" + mExpanded
                     + " mAnimating=" + mAnimating
                     + " mAnimatingReveal=" + mAnimatingReveal
                     + " mAnimY=" + mAnimY
@@ -1267,41 +1187,23 @@
             mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
         }
 
-        if (!mExpandedVisible) {
-            return;
-        }
-
-        int y;
-        if (mAnimating || mAnimatingReveal) {
-            y = (int)mAnimY;
-        } else {
-            y = getExpandedViewMaxHeight()-1;
-        }
-        // Let the fling think that we're open so it goes in the right direction
-        // and doesn't try to re-open the windowshade.
-        mExpanded = true;
-        prepareTracking(y, false);
-        performFling(y, -mSelfCollapseVelocityPx*velocityMultiplier, true);
+        mStatusBarView.collapseAllPanels(true);
     }
 
-    void performExpand() {
-        if (SPEW) Slog.d(TAG, "performExpand: mExpanded=" + mExpanded);
+    @Override
+    public void animateExpand() {
+        if (SPEW) Slog.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
         if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
             return ;
         }
-        if (mExpanded) {
-            return;
-        }
 
-        mExpanded = true;
-        makeExpandedVisible(false);
-        updateExpandedViewPos(EXPANDED_FULL_OPEN);
+        mNotificationPanel.expand();
 
         if (false) postStartTracing();
     }
 
-    void performCollapse() {
-        if (SPEW) Slog.d(TAG, "performCollapse: mExpanded=" + mExpanded
+    void makeExpandedInvisible() {
+        if (SPEW) Slog.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
                 + " mExpandedVisible=" + mExpandedVisible);
 
         if (!mExpandedVisible) {
@@ -1309,7 +1211,7 @@
         }
 
         // Ensure the panel is fully collapsed (just in case; bug 6765842)
-        updateExpandedViewPos(0);
+        mStatusBarView.collapseAllPanels(/*animate=*/ false);
 
         mExpandedVisible = false;
         mPile.setLayoutTransitionsEnabled(false);
@@ -1322,18 +1224,12 @@
         lp.height = getStatusBarHeight();
         lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
         lp.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        final WindowManager wm = WindowManagerImpl.getDefault();
-        wm.updateViewLayout(mStatusBarWindow, lp);
+        mWindowManager.updateViewLayout(mStatusBarWindow, lp);
 
         if ((mDisabled & StatusBarManager.DISABLE_NOTIFICATION_ICONS) == 0) {
             setNotificationIconVisibility(true, com.android.internal.R.anim.fade_in);
         }
 
-        if (!mExpanded) {
-            return;
-        }
-        mExpanded = false;
-
         // Close any "App info" popups that might have snuck on-screen
         dismissPopups();
 
@@ -1343,67 +1239,6 @@
         }
     }
 
-    void resetLastAnimTime() {
-        mAnimLastTimeNanos = System.nanoTime();
-        if (SPEW) {
-            Throwable t = new Throwable();
-            t.fillInStackTrace();
-            Slog.d(TAG, "resetting last anim time=" + mAnimLastTimeNanos, t);
-        }
-    }
-
-    void doAnimation(long frameTimeNanos) {
-        if (mAnimating) {
-            if (SPEW) Slog.d(TAG, "doAnimation dt=" + (frameTimeNanos - mAnimLastTimeNanos));
-            if (SPEW) Slog.d(TAG, "doAnimation before mAnimY=" + mAnimY);
-            incrementAnim(frameTimeNanos);
-            if (SPEW) {
-                Slog.d(TAG, "doAnimation after  mAnimY=" + mAnimY);
-                Slog.d(TAG, "doAnimation expandedViewMax=" + getExpandedViewMaxHeight());
-            }
-
-            if (mAnimY >= getExpandedViewMaxHeight()-1 && !mClosing) {
-                if (SPEW) Slog.d(TAG, "Animation completed to expanded state.");
-                mAnimating = false;
-                updateExpandedViewPos(EXPANDED_FULL_OPEN);
-                performExpand();
-                return;
-            }
-
-            if (mAnimY == 0 && mAnimAccel == 0 && mClosing) {
-                if (SPEW) Slog.d(TAG, "Animation completed to collapsed state.");
-                mAnimating = false;
-                performCollapse();
-                return;
-            }
-
-            if (mAnimY < getStatusBarHeight() && mClosing) {
-                // Draw one more frame with the bar positioned at the top of the screen
-                // before ending the animation so that the user sees the bar in
-                // its final position.  The call to performCollapse() causes a window
-                // relayout which takes time and might cause the animation to skip
-                // on the very last frame before the bar disappears if we did it now.
-                mAnimY = 0;
-                mAnimAccel = 0;
-                mAnimVel = 0;
-            }
-
-            updateExpandedViewPos((int)mAnimY);
-            mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION,
-                    mAnimationCallback, null);
-        }
-    }
-
-    void stopTracking() {
-        if (!mTracking)
-            return;
-        mTracking = false;
-        setPileLayers(View.LAYER_TYPE_NONE);
-        mVelocityTracker.recycle();
-        mVelocityTracker = null;
-        mCloseView.setPressed(false);
-    }
-
     /**
      * Enables or disables layers on the children of the notifications pile.
      * 
@@ -1451,148 +1286,6 @@
         }
     }
 
-    void incrementAnim(long frameTimeNanos) {
-        final long deltaNanos = Math.max(frameTimeNanos - mAnimLastTimeNanos, 0);
-        final float t = deltaNanos * 0.000000001f;                  // ns -> s
-        final float y = mAnimY;
-        final float v = mAnimVel;                                   // px/s
-        final float a = mAnimAccel;                                 // px/s/s
-        mAnimY = y + (v*t) + (0.5f*a*t*t);                          // px
-        mAnimVel = v + (a*t);                                       // px/s
-        mAnimLastTimeNanos = frameTimeNanos;                        // ns
-        //Slog.d(TAG, "y=" + y + " v=" + v + " a=" + a + " t=" + t + " mAnimY=" + mAnimY
-        //        + " mAnimAccel=" + mAnimAccel);
-    }
-
-    void doRevealAnimation(long frameTimeNanos) {
-        if (SPEW) {
-            Slog.d(TAG, "doRevealAnimation: dt=" + (frameTimeNanos - mAnimLastTimeNanos));
-        }
-        final int h = mNotificationPanelMinHeight;
-        if (mAnimatingReveal && mAnimating && mAnimY < h) {
-            incrementAnim(frameTimeNanos);
-            if (mAnimY >= h) {
-                mAnimY = h;
-                updateExpandedViewPos((int)mAnimY);
-            } else {
-                updateExpandedViewPos((int)mAnimY);
-                mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION,
-                        mRevealAnimationCallback, null);
-            }
-        }
-    }
-
-    void prepareTracking(int y, boolean opening) {
-        if (CHATTY) {
-            Slog.d(TAG, "panel: beginning to track the user's touch, y=" + y + " opening=" + opening);
-        }
-
-        mCloseView.setPressed(true);
-
-        mTracking = true;
-        setPileLayers(View.LAYER_TYPE_HARDWARE);
-        mVelocityTracker = VelocityTracker.obtain();
-        if (opening) {
-            makeExpandedVisible(true);
-        } else {
-            // it's open, close it?
-            if (mAnimating) {
-                mAnimating = false;
-                mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
-                        mAnimationCallback, null);
-            }
-            updateExpandedViewPos(y + mViewDelta);
-        }
-    }
-
-    void performFling(int y, float vel, boolean always) {
-        if (CHATTY) {
-            Slog.d(TAG, "panel: will fling, y=" + y + " vel=" + vel + " mExpanded=" + mExpanded);
-        }
-
-        mAnimatingReveal = false;
-
-        mAnimY = y;
-        mAnimVel = vel;
-
-        //Slog.d(TAG, "starting with mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel);
-
-        if (mExpanded) {
-            if (!always && (
-                    vel > mFlingCollapseMinVelocityPx
-                    || (y > (getExpandedViewMaxHeight()*(1f-mCollapseMinDisplayFraction)) &&
-                        vel > -mFlingExpandMinVelocityPx))) {
-                // We are expanded, but they didn't move sufficiently to cause
-                // us to retract.  Animate back to the expanded position.
-                mAnimAccel = mExpandAccelPx;
-                if (vel < 0) {
-                    mAnimVel = 0;
-                }
-            }
-            else {
-                // We are expanded and are now going to animate away.
-                mAnimAccel = -mCollapseAccelPx;
-                if (vel > 0) {
-                    mAnimVel = 0;
-                }
-            }
-        } else {
-            if (always || (
-                    vel > mFlingExpandMinVelocityPx
-                    || (y > (getExpandedViewMaxHeight()*(1f-mExpandMinDisplayFraction)) &&
-                        vel > -mFlingCollapseMinVelocityPx))) {
-                // We are collapsed, and they moved enough to allow us to
-                // expand.  Animate in the notifications.
-                mAnimAccel = mExpandAccelPx;
-                if (vel < 0) {
-                    mAnimVel = 0;
-                }
-            }
-            else {
-                // We are collapsed, but they didn't move sufficiently to cause
-                // us to retract.  Animate back to the collapsed position.
-                mAnimAccel = -mCollapseAccelPx;
-                if (vel > 0) {
-                    mAnimVel = 0;
-                }
-            }
-        }
-        //Slog.d(TAG, "mAnimY=" + mAnimY + " mAnimVel=" + mAnimVel
-        //        + " mAnimAccel=" + mAnimAccel);
-
-        resetLastAnimTime();
-        mAnimating = true;
-        mClosing = mAnimAccel < 0;
-
-        mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
-                mAnimationCallback, null);
-        mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION,
-                mRevealAnimationCallback, null);
-        mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION,
-                mAnimationCallback, null);
-        stopTracking();
-    }
-
-    boolean handleUniverseEvent(MotionEvent event) {
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return false;
-        }
-        if (mExpanded) {
-            return false;
-        }
-        if (mUniverseBackground.consumeEvent(event)) {
-            if (mTracking) {
-                // fling back to the top, starting from the last tracked position.
-                mFlingY = mTrackingPosition;
-                mViewDelta = 0;
-                mFlingVelocity = -1;
-                mHandler.post(mPerformFling);
-            }
-            return true;
-        }
-        return false;
-    }
-
     boolean interceptTouchEvent(MotionEvent event) {
         if (SPEW) {
             Slog.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled="
@@ -1608,108 +1301,11 @@
 
         mGestureRec.add(event);
 
-        if ((mDisabled & StatusBarManager.DISABLE_EXPAND) != 0) {
-            return false;
-        }
-
-        final int y = (int)event.getRawY();
-        final int action = event.getAction();
-        final int statusBarSize = getStatusBarHeight();
-        final int hitSize = statusBarSize*2;
-        if (action == MotionEvent.ACTION_DOWN) {
-            if (!areLightsOn()) {
-                setLightsOn(true);
-            }
-
-            if (!mExpanded) {
-                mViewDelta = statusBarSize - y;
-            } else {
-                mCloseView.getLocationOnScreen(mAbsPos);
-                mViewDelta = mAbsPos[1]
-                           + getCloseViewHeight() // XXX: not closeViewHeight, but paddingBottom from the 9patch
-                           + mNotificationPanelBackgroundPadding.top
-                           + mNotificationPanelBackgroundPadding.bottom
-                           - y;
-            }
-            if ((!mExpanded && y < hitSize) ||
-                    // @@ add taps outside the panel if it's not full-screen
-                    (mExpanded && y > (getExpandedViewMaxHeight()-hitSize))) {
-                // We drop events at the edge of the screen to make the windowshade come
-                // down by accident less, especially when pushing open a device with a keyboard
-                // that rotates (like g1 and droid)
-                int x = (int)event.getRawX();
-                final int edgeBorder = mEdgeBorder;
-                if (x >= edgeBorder && x < mDisplayMetrics.widthPixels - edgeBorder) {
-                    prepareTracking(y, !mExpanded);// opening if we're not already fully visible
-                    trackMovement(event);
-                    mGestureRec.tag("tracking", mExpanded ? "expanded" : "collapsed");
-                }
-            }
-        } else if (mTracking) {
-            trackMovement(event);
-            if (action == MotionEvent.ACTION_MOVE) {
-                if (mAnimatingReveal && (y + mViewDelta) < mNotificationPanelMinHeight) {
-                    // nothing
-                } else  {
-                    mAnimatingReveal = false;
-                    updateExpandedViewPos(y + mViewDelta);
-                }
-            } else if (action == MotionEvent.ACTION_UP
-                    || action == MotionEvent.ACTION_CANCEL) {
-                mVelocityTracker.computeCurrentVelocity(1000);
-
-                float yVel = mVelocityTracker.getYVelocity();
-                boolean negative = yVel < 0;
-
-                float xVel = mVelocityTracker.getXVelocity();
-                if (xVel < 0) {
-                    xVel = -xVel;
-                }
-                if (xVel > mFlingGestureMaxXVelocityPx) {
-                    xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
-                }
-
-                float vel = (float)Math.hypot(yVel, xVel);
-                if (vel > mFlingGestureMaxOutputVelocityPx) {
-                    vel = mFlingGestureMaxOutputVelocityPx;
-                }
-                if (negative) {
-                    vel = -vel;
-                }
-
-                if (CHATTY) {
-                    Slog.d(TAG, String.format("gesture: vraw=(%f,%f) vnorm=(%f,%f) vlinear=%f",
-                        mVelocityTracker.getXVelocity(),
-                        mVelocityTracker.getYVelocity(),
-                        xVel, yVel,
-                        vel));
-                }
-
-                if (mTrackingPosition == mNotificationPanelMinHeight) {
-                    // start the fling from the tracking position, ignore y and view delta
-                    mFlingY = mTrackingPosition;
-                    mViewDelta = 0;
-                } else {
-                    mFlingY = y;
-                }
-                mFlingVelocity = vel;
-                mGestureRec.tag("fling " + ((mFlingVelocity > 0) ? "open" : "closed"),
-                                "v=" + mFlingVelocity);
-                mHandler.post(mPerformFling);
-            }
-
-        }
         return false;
     }
 
-    private void trackMovement(MotionEvent event) {
-        // Add movement to velocity tracker using raw screen X and Y coordinates instead
-        // of window coordinates because the window frame may be moving at the same time.
-        float deltaX = event.getRawX() - event.getX();
-        float deltaY = event.getRawY() - event.getY();
-        event.offsetLocation(deltaX, deltaY);
-        mVelocityTracker.addMovement(event);
-        event.offsetLocation(-deltaX, -deltaY);
+    public GestureRecorder getGestureRecorder() {
+        return mGestureRec;
     }
 
     @Override // CommandQueue
@@ -1805,7 +1401,7 @@
 
     private void notifyUiVisibilityChanged() {
         try {
-            mWindowManager.statusBarVisibilityChanged(mSystemUiVisibility);
+            mWindowManagerService.statusBarVisibilityChanged(mSystemUiVisibility);
         } catch (RemoteException ex) {
         }
     }
@@ -1913,8 +1509,7 @@
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         synchronized (mQueueLock) {
             pw.println("Current Status Bar state:");
-            pw.println("  mExpanded=" + mExpanded
-                    + ", mExpandedVisible=" + mExpandedVisible
+            pw.println("  mExpandedVisible=" + mExpandedVisible
                     + ", mTrackingPosition=" + mTrackingPosition);
             pw.println("  mTicking=" + mTicking);
             pw.println("  mTracking=" + mTracking);
@@ -1930,7 +1525,6 @@
                     + " mViewDelta=" + mViewDelta);
             pw.println("  mDisplayMetrics=" + mDisplayMetrics);
             pw.println("  mPile: " + viewInfo(mPile));
-            pw.println("  mCloseView: " + viewInfo(mCloseView));
             pw.println("  mTickerView: " + viewInfo(mTickerView));
             pw.println("  mScrollView: " + viewInfo(mScrollView)
                     + " scroll " + mScrollView.getScrollX() + "," + mScrollView.getScrollY());
@@ -2013,7 +1607,7 @@
         lp.packageName = mContext.getPackageName();
 
         makeStatusBarView();
-        WindowManagerImpl.getDefault().addView(mStatusBarWindow, lp);
+        mWindowManager.addView(mStatusBarWindow, lp);
     }
 
     void setNotificationIconVisibility(boolean visible, int anim) {
@@ -2039,83 +1633,17 @@
     }
 
     @Override
-    protected void updateExpandedViewPos(int expandedPosition) {
-        if (SPEW) {
-            Slog.d(TAG, "updateExpandedViewPos: expandedPosition=" + expandedPosition
-                    //+ " mTrackingParams.y=" + ((mTrackingParams == null) ? "?" : mTrackingParams.y)
-                    + " mTracking=" + mTracking
-                    + " mTrackingPosition=" + mTrackingPosition
-                    + " mExpandedVisible=" + mExpandedVisible
-                    + " mAnimating=" + mAnimating
-                    + " mAnimatingReveal=" + mAnimatingReveal
-                    + " mClosing=" + mClosing
-                    + " gravity=" + mNotificationPanelGravity);
-        }
-        int panelh = 0;
-        final int disph = getExpandedViewMaxHeight();
-
-        // If the expanded view is not visible, make sure they're still off screen.
-        // Maybe the view was resized.
-        if (!mExpandedVisible) {
-            if (SPEW) Slog.d(TAG, "updateExpandedViewPos: view not visible, bailing");
-            updateExpandedInvisiblePosition();
-            return;
-        }
-
-        // tracking view...
-        if (expandedPosition == EXPANDED_FULL_OPEN) {
-            panelh = disph;
-        }
-        else if (expandedPosition == EXPANDED_LEAVE_ALONE) {
-            panelh = mTrackingPosition;
-        }
-        else {
-            if (expandedPosition <= disph) {
-                panelh = expandedPosition;
-            } else {
-                panelh = disph;
-            }
-        }
-
-        // catch orientation changes and other peculiar cases
-        if (panelh > 0 &&
-                ((panelh > disph) ||
-                 (panelh < disph && !mTracking && !mAnimating))) {
-            if (SPEW) Slog.d(TAG, "updateExpandedViewPos: orientation change?");
-            panelh = disph;
-        } else if (panelh < 0) {
-            panelh = 0;
-        }
-
-        if (SPEW) Slog.d(TAG, "updateExpandedViewPos: adjusting size to panelh=" + panelh);
-
-        if (panelh == mTrackingPosition) {
-            if (SPEW) Slog.d(TAG, "updateExpandedViewPos: panelh == mTrackingPosition, bailing");
-            return;
-        }
-
-        mTrackingPosition = panelh;
-
+    public void updateExpandedViewPos(int thingy) {
+        // TODO
+        if (DEBUG) Slog.v(TAG, "updateExpandedViewPos");
         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams();
-        lp.height = panelh;
         lp.gravity = mNotificationPanelGravity;
-        lp.leftMargin = mNotificationPanelMarginLeftPx;
-        if (SPEW) {
-            Slog.v(TAG, "updated cropView height=" + panelh + " grav=" + lp.gravity);
-        }
+        lp.leftMargin = mNotificationPanelMarginPx;
         mNotificationPanel.setLayoutParams(lp);
-
-        final int barh = getCloseViewHeight() + getStatusBarHeight();
-        final float frac = saturate((float)(panelh - barh) / (disph - barh));
-
-        if (DIM_BEHIND_EXPANDED_PANEL && ActivityManager.isHighEndGfx(mDisplay)) {
-            // woo, special effects
-            final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2.2f))));
-            final int color = ((int)(0xB0 * k)) << 24;
-            mStatusBarWindow.setBackgroundColor(color);
-        }
-        
-        updateCarrierLabelVisibility(false);
+        lp = (FrameLayout.LayoutParams) mSettingsPanel.getLayoutParams();
+        lp.gravity = mSettingsPanelGravity;
+        lp.rightMargin = mNotificationPanelMarginPx;
+        mSettingsPanel.setLayoutParams(lp);
     }
 
     // called by makeStatusbar and also by PhoneStatusBarView
@@ -2196,6 +1724,9 @@
                         mPostCollapseCleanup = new Runnable() {
                             @Override
                             public void run() {
+                                if (DEBUG) {
+                                    Slog.v(TAG, "running post-collapse cleanup");
+                                }
                                 try {
                                     mPile.setViewRemoval(true);
                                     mBarService.onClearAllNotifications();
@@ -2244,13 +1775,15 @@
             } catch (RemoteException e) {
             }
             v.getContext().startActivityAsUser(new Intent(Settings.ACTION_SETTINGS)
-                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), UserId.USER_CURRENT);
+                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
+                    new UserHandle(UserHandle.USER_CURRENT));
             animateCollapse();
         }
     };
 
     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
+            Slog.v(TAG, "onReceive: " + intent);
             String action = intent.getAction();
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
                 int flags = CommandQueue.FLAG_EXCLUDE_NONE;
@@ -2264,7 +1797,7 @@
             }
             else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                 // no waiting!
-                performCollapse();
+                makeExpandedInvisible();
             }
             else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
                 updateResources();
@@ -2274,6 +1807,13 @@
         }
     };
 
+    @Override
+    public void userSwitched(int newUserId) {
+        if (MULTIUSER_DEBUG) mNotificationPanelDebugText.setText("USER " + newUserId);
+        animateCollapse();
+        updateNotificationIcons();
+    }
+    
     private void setIntruderAlertVisibility(boolean vis) {
         if (!ENABLE_INTRUDERS) return;
         if (DEBUG) {
@@ -2349,11 +1889,15 @@
 
         mNotificationPanelMarginBottomPx
             = (int) res.getDimension(R.dimen.notification_panel_margin_bottom);
-        mNotificationPanelMarginLeftPx
+        mNotificationPanelMarginPx
             = (int) res.getDimension(R.dimen.notification_panel_margin_left);
         mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity);
         if (mNotificationPanelGravity <= 0) {
-            mNotificationPanelGravity = Gravity.CENTER_VERTICAL | Gravity.TOP;
+            mNotificationPanelGravity = Gravity.LEFT | Gravity.TOP;
+        }
+        mSettingsPanelGravity = res.getInteger(R.integer.settings_panel_layout_gravity);
+        if (mSettingsPanelGravity <= 0) {
+            mSettingsPanelGravity = Gravity.RIGHT | Gravity.TOP;
         }
         getNinePatchPadding(res.getDrawable(R.drawable.notification_panel_bg), mNotificationPanelBackgroundPadding);
         final int notificationPanelDecorationHeight =
@@ -2416,7 +1960,7 @@
 
     @Override
     protected boolean shouldDisableNavbarGestures() {
-        return mExpanded || (mDisabled & StatusBarManager.DISABLE_HOME) != 0;
+        return mExpandedVisible || (mDisabled & StatusBarManager.DISABLE_HOME) != 0;
     }
 
     private static class FastColorDrawable extends Drawable {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index fd4cff8..6d47493 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -16,9 +16,13 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.app.ActivityManager;
+import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.SystemClock;
 import android.util.AttributeSet;
@@ -35,133 +39,40 @@
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.policy.FixedSizeDrawable;
 
-public class PhoneStatusBarView extends FrameLayout {
+public class PhoneStatusBarView extends PanelBar {
     private static final String TAG = "PhoneStatusBarView";
-
-    static final int DIM_ANIM_TIME = 400;
-    
-    PhoneStatusBar mService;
-    boolean mTracking;
-    int mStartX, mStartY;
-    ViewGroup mNotificationIcons;
-    ViewGroup mStatusIcons;
-    
-    boolean mNightMode = false;
-    int mStartAlpha = 0, mEndAlpha = 0;
-    long mEndTime = 0;
-
-    Rect mButtonBounds = new Rect();
-    boolean mCapturingEvents = true;
+    PhoneStatusBar mBar;
+    int mScrimColor;
+    PanelView mFadingPanel = null;
+    PanelView mNotificationPanel, mSettingsPanel;
 
     public PhoneStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mNotificationIcons = (ViewGroup)findViewById(R.id.notificationIcons);
-        mStatusIcons = (ViewGroup)findViewById(R.id.statusIcons);
+    public void setBar(PhoneStatusBar bar) {
+        mBar = bar;
     }
 
     @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        //mService.onBarViewAttached();
-    }
-    
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        mService.updateDisplaySize();
-        boolean nightMode = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
-                == Configuration.UI_MODE_NIGHT_YES;
-        if (mNightMode != nightMode) {
-            mNightMode = nightMode;
-            mStartAlpha = getCurAlpha();
-            mEndAlpha = mNightMode ? 0x80 : 0x00;
-            mEndTime = SystemClock.uptimeMillis() + DIM_ANIM_TIME;
-            invalidate();
-        }
-    }
-
-    int getCurAlpha() {
-        long time = SystemClock.uptimeMillis();
-        if (time > mEndTime) {
-            return mEndAlpha;
-        }
-        return mEndAlpha
-                - (int)(((mEndAlpha-mStartAlpha) * (mEndTime-time) / DIM_ANIM_TIME));
-    }
-    
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-        mService.updateExpandedViewPos(BaseStatusBar.EXPANDED_LEAVE_ALONE);
+    public void onAttachedToWindow() {
+        Resources res = getContext().getResources();
+        mScrimColor = res.getColor(R.color.notification_panel_scrim_color);
     }
 
     @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
+    public void addPanel(PanelView pv) {
+        super.addPanel(pv);
+        if (pv.getId() == R.id.notification_panel) {
+            mNotificationPanel = pv;
+        } else if (pv.getId() == R.id.settings_panel){
+            mSettingsPanel = pv;
+        }
     }
 
     @Override
-    protected void dispatchDraw(Canvas canvas) {
-        super.dispatchDraw(canvas);
-        int alpha = getCurAlpha();
-        if (alpha != 0) {
-            canvas.drawARGB(alpha, 0, 0, 0);
-        }
-        if (alpha != mEndAlpha) {
-            invalidate();
-        }
-    }
-
-    /**
-     * Gets the left position of v in this view.  Throws if v is not
-     * a child of this.
-     */
-    private int getViewOffset(View v) {
-        int offset = 0;
-        while (v != this) {
-            offset += v.getLeft();
-            ViewParent p = v.getParent();
-            if (v instanceof View) {
-                v = (View)p;
-            } else {
-                throw new RuntimeException(v + " is not a child of " + this);
-            }
-        }
-        return offset;
-    }
-
-    /**
-     * Ensure that, if there is no target under us to receive the touch,
-     * that we process it ourself.  This makes sure that onInterceptTouchEvent()
-     * is always called for the entire gesture.
-     */
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        if (!mCapturingEvents) {
-            return false;
-        }
-        if (event.getAction() != MotionEvent.ACTION_DOWN) {
-            mService.interceptTouchEvent(event);
-        }
-        return true;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            if (mButtonBounds.contains((int)event.getX(), (int)event.getY())) {
-                mCapturingEvents = false;
-                return false;
-            }
-        }
-        mCapturingEvents = true;
-        return mService.interceptTouchEvent(event)
-                ? true : super.onInterceptTouchEvent(event);
+    public boolean panelsEnabled() {
+        return ((mBar.mDisabled & StatusBarManager.DISABLE_EXPAND) == 0);
     }
 
     @Override
@@ -178,4 +89,67 @@
         }
         return false;
     }
+
+    @Override
+    public PanelView selectPanelForTouchX(float x) {
+        // We split the status bar into thirds: the left 2/3 are for notifications, and the 
+        // right 1/3 for quick settings. If you pull the status bar down a second time you'll
+        // toggle panels no matter where you pull it down.
+        final float w = (float) getMeasuredWidth();
+        final float f = x / w;
+        if (f > 0.67f && mSettingsPanel.getExpandedFraction() != 1.0f
+                || mNotificationPanel.getExpandedFraction() == 1.0f) {
+            return mSettingsPanel;
+        }
+        return mNotificationPanel;
+    }
+
+    @Override
+    public void onPanelPeeked() {
+        super.onPanelPeeked();
+        mBar.makeExpandedVisible(true);
+        if (mFadingPanel == null) {
+            mFadingPanel = mTouchingPanel;
+        }
+    }
+
+    @Override
+    public void onAllPanelsCollapsed() {
+        super.onAllPanelsCollapsed();
+        mBar.makeExpandedInvisible();
+        mFadingPanel = null;
+    }
+
+    @Override
+    public void onPanelFullyOpened(PanelView openPanel) {
+        mFadingPanel = openPanel;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        return mBar.interceptTouchEvent(event) || super.onTouchEvent(event);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        return mBar.interceptTouchEvent(event) || super.onInterceptTouchEvent(event);
+    }
+
+    @Override
+    public void panelExpansionChanged(PanelView pv, float frac) {
+        super.panelExpansionChanged(pv, frac);
+
+        if (mFadingPanel == pv 
+                && mScrimColor != 0 && ActivityManager.isHighEndGfx()) {
+            // woo, special effects
+            final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2.2f))));
+            // attenuate background color alpha by k
+            final int color = (int) ((float)(mScrimColor >>> 24) * k) << 24 | (mScrimColor & 0xFFFFFF);
+            mBar.mStatusBarWindow.setBackgroundColor(color);
+        }
+
+        mBar.updateCarrierLabelVisibility(false);
+    }
+
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
new file mode 100644
index 0000000..fb1528f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsPanelView.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+public class SettingsPanelView extends PanelView {
+    public SettingsPanelView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void fling(float vel, boolean always) {
+        ((PhoneStatusBarView) mBar).mBar.getGestureRecorder().tag(
+            "fling " + ((vel > 0) ? "open" : "closed"),
+            "settings,v=" + vel);
+        super.fling(vel, always);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index f53ed0c..2d4c9ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -37,8 +37,6 @@
     private ExpandHelper mExpandHelper;
     private NotificationRowLayout latestItems;
 
-    private boolean mUniverseHandling = false;
-
     PhoneStatusBar mService;
 
     public StatusBarWindowView(Context context, AttributeSet attrs) {
@@ -73,16 +71,6 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (mService.handleUniverseEvent(ev)) {
-            mUniverseHandling = true;
-            MotionEvent cancellation = MotionEvent.obtain(ev);
-            cancellation.setAction(MotionEvent.ACTION_CANCEL);
-            mExpandHelper.onInterceptTouchEvent(cancellation);
-            latestItems.onInterceptTouchEvent(cancellation);
-            cancellation.recycle();
-            return true;
-        }
-
         boolean intercept = mExpandHelper.onInterceptTouchEvent(ev) ||
                 super.onInterceptTouchEvent(ev);
         if (intercept) {
@@ -96,12 +84,6 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
-        if (mUniverseHandling) {
-            if (!mService.handleUniverseEvent(ev)) {
-                mUniverseHandling = false;
-            }
-            return true;
-        }
         boolean handled = mExpandHelper.onTouchEvent(ev) ||
                 super.onTouchEvent(ev);
         return handled;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
index 3ba36af..457e9dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessController.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.os.AsyncTask;
 import android.os.IPowerManager;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
@@ -31,8 +32,8 @@
 public class BrightnessController implements ToggleSlider.Listener {
     private static final String TAG = "StatusBar.BrightnessController";
 
-    private static final int MINIMUM_BACKLIGHT = android.os.PowerManager.BRIGHTNESS_DIM;
-    private static final int MAXIMUM_BACKLIGHT = android.os.PowerManager.BRIGHTNESS_ON;
+    private final int mMinimumBacklight;
+    private final int mMaximumBacklight;
 
     private Context mContext;
     private ToggleSlider mControl;
@@ -42,6 +43,10 @@
         mContext = context;
         mControl = control;
 
+        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mMinimumBacklight = pm.getMinimumScreenBrightnessSetting();
+        mMaximumBacklight = pm.getMaximumScreenBrightnessSetting();
+
         boolean automaticAvailable = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_automatic_brightness_available);
         mPower = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
@@ -65,11 +70,11 @@
             value = Settings.System.getInt(mContext.getContentResolver(), 
                     Settings.System.SCREEN_BRIGHTNESS);
         } catch (SettingNotFoundException ex) {
-            value = MAXIMUM_BACKLIGHT;
+            value = mMaximumBacklight;
         }
 
-        control.setMax(MAXIMUM_BACKLIGHT - MINIMUM_BACKLIGHT);
-        control.setValue(value - MINIMUM_BACKLIGHT);
+        control.setMax(mMaximumBacklight - mMinimumBacklight);
+        control.setValue(value - mMinimumBacklight);
 
         control.setOnChangedListener(this);
     }
@@ -78,7 +83,7 @@
         setMode(automatic ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
                 : Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
         if (!automatic) {
-            final int val = value + MINIMUM_BACKLIGHT;
+            final int val = value + mMinimumBacklight;
             setBrightness(val);
             if (!tracking) {
                 AsyncTask.execute(new Runnable() {
@@ -98,7 +103,7 @@
     
     private void setBrightness(int brightness) {
         try {
-            mPower.setBacklightBrightness(brightness);
+            mPower.setTemporaryScreenBrightnessSettingOverride(brightness);
         } catch (RemoteException ex) {
         }        
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 69872df..ffc18c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -34,6 +34,7 @@
 import android.text.style.RelativeSizeSpan;
 import android.text.style.StyleSpan;
 import android.util.AttributeSet;
+import android.util.Slog;
 import android.view.View;
 import android.widget.TextView;
 
@@ -173,7 +174,6 @@
                         + "a" + MAGIC2 + format.substring(b + 1);
                 }
             }
-
             mClockFormat = sdf = new SimpleDateFormat(format);
             mClockFormatString = format;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index 9fee49b..89eed1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -78,6 +78,7 @@
         super(context, attrs, defStyle);
 
         mRealLayoutTransition = new LayoutTransition();
+        mRealLayoutTransition.setAnimateParentHierarchy(true);
         setLayoutTransitionsEnabled(true);
         
         setOrientation(LinearLayout.VERTICAL);
@@ -166,6 +167,7 @@
     }
 
     public void onChildDismissed(View v) {
+        if (DEBUG) Slog.v(TAG, "onChildDismissed: " + v + " mRemoveViews=" + mRemoveViews);
         final View veto = v.findViewById(R.id.veto);
         if (veto != null && veto.getVisibility() != View.GONE && mRemoveViews) {
             veto.performClick();
@@ -229,6 +231,7 @@
      * get removed properly.
      */
     public void setViewRemoval(boolean removeViews) {
+        if (DEBUG) Slog.v(TAG, "setViewRemoval: " + removeViews);
         mRemoveViews = removeViews;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
index da161a9..c45ac3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
@@ -19,7 +19,7 @@
 import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.Intent;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Slog;
@@ -119,7 +119,8 @@
     // ----------------------------
     private void onClickSettings() {
         getContext().startActivityAsUser(new Intent(Settings.ACTION_SETTINGS)
-                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), UserId.USER_CURRENT);
+                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
+                new UserHandle(UserHandle.USER_CURRENT));
         getStatusBarManager().collapse();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
index ddb43b8..2924cc9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
@@ -34,7 +34,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.WindowManagerImpl;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index cbd8831..84697e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -53,7 +53,6 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowManager;
-import android.view.WindowManagerImpl;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -124,8 +123,6 @@
     int mMenuNavIconWidth = -1;
     private int mMaxNotificationIcons = 5;
 
-    IWindowManager mWindowManager;
-
     TabletStatusBarView mStatusBarView;
     View mNotificationArea;
     View mNotificationTrigger;
@@ -241,7 +238,7 @@
         lp.gravity = getStatusBarGravity();
         lp.setTitle("SystemBar");
         lp.packageName = mContext.getPackageName();
-        WindowManagerImpl.getDefault().addView(sb, lp);
+        mWindowManager.addView(sb, lp);
     }
 
     protected void addPanelWindows() {
@@ -306,7 +303,7 @@
         lp.windowAnimations = com.android.internal.R.style.Animation; // == no animation
 //        lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons; // simple fade
 
-        WindowManagerImpl.getDefault().addView(mNotificationPanel, lp);
+        mWindowManager.addView(mNotificationPanel, lp);
 
         // Recents Panel
         mRecentTasksLoader = new RecentTasksLoader(context);
@@ -338,7 +335,7 @@
         lp.setTitle("InputMethodsPanel");
         lp.windowAnimations = R.style.Animation_RecentPanel;
 
-        WindowManagerImpl.getDefault().addView(mInputMethodsPanel, lp);
+        mWindowManager.addView(mInputMethodsPanel, lp);
 
         // Compatibility mode selector panel
         mCompatModePanel = (CompatModePanel) View.inflate(context,
@@ -361,7 +358,7 @@
         lp.setTitle("CompatModePanel");
         lp.windowAnimations = android.R.style.Animation_Dialog;
 
-        WindowManagerImpl.getDefault().addView(mCompatModePanel, lp);
+        mWindowManager.addView(mCompatModePanel, lp);
 
         mRecentButton.setOnTouchListener(mRecentsPanel);
 
@@ -380,7 +377,7 @@
 
     private int getNotificationPanelHeight() {
         final Resources res = mContext.getResources();
-        final Display d = WindowManagerImpl.getDefault().getDefaultDisplay();
+        final Display d = mWindowManager.getDefaultDisplay();
         final Point size = new Point();
         d.getRealSize(size);
         return Math.max(res.getDimensionPixelSize(R.dimen.notification_panel_min_height), size.y);
@@ -395,8 +392,7 @@
     protected void onConfigurationChanged(Configuration newConfig) {
         loadDimens();
         mNotificationPanelParams.height = getNotificationPanelHeight();
-        WindowManagerImpl.getDefault().updateViewLayout(mNotificationPanel,
-                mNotificationPanelParams);
+        mWindowManager.updateViewLayout(mNotificationPanel, mNotificationPanelParams);
         mRecentsPanel.updateValuesFromResources();
         mShowSearchHoldoff = mContext.getResources().getInteger(
                 R.integer.config_show_search_delay);
@@ -456,9 +452,6 @@
     protected View makeStatusBarView() {
         final Context context = mContext;
 
-        mWindowManager = IWindowManager.Stub.asInterface(
-                ServiceManager.getService(Context.WINDOW_SERVICE));
-
         loadDimens();
 
         final TabletStatusBarView sb = (TabletStatusBarView)View.inflate(
@@ -470,7 +463,7 @@
         try {
             // Sanity-check that someone hasn't set up the config wrong and asked for a navigation
             // bar on a tablet that has only the system bar
-            if (mWindowManager.hasNavigationBar()) {
+            if (mWindowManagerService.hasNavigationBar()) {
                 Slog.e(TAG, "Tablet device cannot show navigation bar and system bar");
             }
         } catch (RemoteException ex) {
@@ -648,7 +641,7 @@
                         | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
                         | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
                 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
-        if (ActivityManager.isHighEndGfx(mDisplay)) {
+        if (ActivityManager.isHighEndGfx()) {
             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         } else {
             lp.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
@@ -681,7 +674,7 @@
         WindowManager.LayoutParams lp =
             (android.view.WindowManager.LayoutParams) mStatusBarView.getLayoutParams();
         lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-        WindowManagerImpl.getDefault().updateViewLayout(mStatusBarView, lp);
+        mWindowManager.updateViewLayout(mStatusBarView, lp);
     }
 
     @Override
@@ -690,7 +683,7 @@
         WindowManager.LayoutParams lp =
             (android.view.WindowManager.LayoutParams) mStatusBarView.getLayoutParams();
         lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-        WindowManagerImpl.getDefault().updateViewLayout(mStatusBarView, lp);
+        mWindowManager.updateViewLayout(mStatusBarView, lp);
     }
 
     public int getStatusBarHeight() {
@@ -712,8 +705,7 @@
         }
         if (lp.height != height) {
             lp.height = height;
-            final WindowManager wm = WindowManagerImpl.getDefault();
-            wm.updateViewLayout(mStatusBarView, lp);
+            mWindowManager.updateViewLayout(mStatusBarView, lp);
         }
     }
 
@@ -1068,7 +1060,7 @@
 
     private void notifyUiVisibilityChanged() {
         try {
-            mWindowManager.statusBarVisibilityChanged(mSystemUiVisibility);
+            mWindowManagerService.statusBarVisibilityChanged(mSystemUiVisibility);
         } catch (RemoteException ex) {
         }
     }
@@ -1160,12 +1152,12 @@
                 | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
         lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons; // simple fade
 
-        WindowManagerImpl.getDefault().addView(mCompatibilityHelpDialog, lp);
+        mWindowManager.addView(mCompatibilityHelpDialog, lp);
     }
 
     private void hideCompatibilityHelp() {
         if (mCompatibilityHelpDialog != null) {
-            WindowManagerImpl.getDefault().removeView(mCompatibilityHelpDialog);
+            mWindowManager.removeView(mCompatibilityHelpDialog);
             mCompatibilityHelpDialog = null;
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
index d4ebe6d..932b035 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
@@ -35,7 +35,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
-import android.view.WindowManagerImpl;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.FrameLayout;
@@ -62,7 +61,8 @@
 
     private static final int ADVANCE_DELAY = 5000; // 5 seconds
 
-    private Context mContext;
+    private final Context mContext;
+    private final WindowManager mWindowManager;
 
     private ViewGroup mWindow;
     private IBinder mCurrentKey;
@@ -83,6 +83,7 @@
     public TabletTicker(TabletStatusBar bar) {
         mBar = bar;
         mContext = bar.getContext();
+        mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
         final Resources res = mContext.getResources();
         mLargeIconHeight = res.getDimensionPixelSize(
                 android.R.dimen.notification_large_icon_height);
@@ -178,7 +179,7 @@
             if (mCurrentView != null) {
                 if (mWindow == null) {
                     mWindow = makeWindow();
-                    WindowManagerImpl.getDefault().addView(mWindow, mWindow.getLayoutParams());
+                    mWindowManager.addView(mWindow, mWindow.getLayoutParams());
                 }
 
                 mWindow.addView(mCurrentView);
@@ -242,7 +243,7 @@
     public void endTransition(LayoutTransition transition, ViewGroup container,
             View view, int transitionType) {
         if (mWindowShouldClose) {
-            WindowManagerImpl.getDefault().removeView(mWindow);
+            mWindowManager.removeView(mWindow);
             mWindow = null;
             mWindowShouldClose = false;
             mBar.doneTicking();
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
new file mode 100644
index 0000000..9146ccd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDebuggingActivity.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.usb;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Typeface;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+import com.android.systemui.R;
+
+public class UsbDebuggingActivity extends AlertActivity
+                                  implements DialogInterface.OnClickListener {
+    private static final String TAG = "UsbDebuggingActivity";
+
+    private CheckBox mAlwaysAllow;
+    private UsbDisconnectedReceiver mDisconnectedReceiver;
+    private String mKey;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
+        Intent intent = getIntent();
+        String fingerprints = intent.getStringExtra("fingerprints");
+        mKey = intent.getStringExtra("key");
+
+        if (fingerprints == null || mKey == null) {
+            finish();
+            return;
+        }
+
+        final AlertController.AlertParams ap = mAlertParams;
+        ap.mTitle = getString(R.string.usb_debugging_title);
+        ap.mIconId = com.android.internal.R.drawable.ic_dialog_usb;
+        ap.mMessage = getString(R.string.usb_debugging_message, fingerprints);
+        ap.mPositiveButtonText = getString(android.R.string.ok);
+        ap.mNegativeButtonText = getString(android.R.string.cancel);
+        ap.mPositiveButtonListener = this;
+        ap.mNegativeButtonListener = this;
+
+        // add "always allow" checkbox
+        LayoutInflater inflater = LayoutInflater.from(ap.mContext);
+        View checkbox = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
+        mAlwaysAllow = (CheckBox)checkbox.findViewById(com.android.internal.R.id.alwaysUse);
+        mAlwaysAllow.setText(getString(R.string.usb_debugging_always));
+        ap.mView = checkbox;
+
+        setupAlert();
+    }
+
+    private class UsbDisconnectedReceiver extends BroadcastReceiver {
+        private final Activity mActivity;
+        public UsbDisconnectedReceiver(Activity activity) {
+            mActivity = activity;
+        }
+
+        @Override
+        public void onReceive(Context content, Intent intent) {
+            String action = intent.getAction();
+            if (!UsbManager.ACTION_USB_STATE.equals(action)) {
+                return;
+            }
+            boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
+            if (!connected) {
+                mActivity.finish();
+            }
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE);
+        registerReceiver(mDisconnectedReceiver, filter);
+    }
+
+    @Override
+    protected void onStop() {
+        if (mDisconnectedReceiver != null) {
+            unregisterReceiver(mDisconnectedReceiver);
+        }
+        super.onStop();
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        boolean allow = (which == AlertDialog.BUTTON_POSITIVE);
+        boolean alwaysAllow = allow && mAlwaysAllow.isChecked();
+        try {
+            IBinder b = ServiceManager.getService(USB_SERVICE);
+            IUsbManager service = IUsbManager.Stub.asInterface(b);
+            if (allow) {
+                service.allowUsbDebugging(alwaysAllow, mKey);
+            } else {
+                service.denyUsbDebugging();
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Unable to notify Usb service", e);
+        }
+        finish();
+    }
+}
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index a0e3e3c..8d19f34 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -50,6 +50,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicy.WindowManagerFuncs;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
@@ -90,8 +91,6 @@
     private boolean mHasTelephony;
     private boolean mHasVibrator;
 
-    private IWindowManager mIWindowManager;
-
     /**
      * @param context everything needs a context :(
      */
@@ -210,11 +209,11 @@
 
                 public void onPress() {
                     // shutdown by making sure radio and power are handled accordingly.
-                    mWindowManagerFuncs.shutdown();
+                    mWindowManagerFuncs.shutdown(true);
                 }
 
                 public boolean onLongPress() {
-                    mWindowManagerFuncs.rebootSafeMode();
+                    mWindowManagerFuncs.rebootSafeMode(true);
                     return true;
                 }
 
@@ -300,7 +299,7 @@
                     public void onPress() {
                         try {
                             ActivityManagerNative.getDefault().switchUser(user.id);
-                            getWindowManager().lockNow();
+                            WindowManagerGlobal.getWindowManagerService().lockNow();
                         } catch (RemoteException re) {
                             Log.e(TAG, "Couldn't switch user " + re);
                         }
@@ -873,12 +872,4 @@
             mAirplaneState = on ? ToggleAction.State.On : ToggleAction.State.Off;
         }
     }
-
-    private IWindowManager getWindowManager() {
-        if (mIWindowManager == null) {
-            IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
-            mIWindowManager = IWindowManager.Stub.asInterface(b);
-        }
-        return mIWindowManager;
-    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
index a939222..5c0cd4f 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
@@ -178,10 +178,10 @@
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_DPM_STATE_CHANGED));
             } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED,
-                        intent.getIntExtra(Intent.EXTRA_USERID, 0), 0));
+                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_REMOVED,
-                        intent.getIntExtra(Intent.EXTRA_USERID, 0), 0));
+                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
             }
         }
     };
@@ -259,7 +259,8 @@
          */
         boolean isPluggedIn() {
             return plugged == BatteryManager.BATTERY_PLUGGED_AC
-                    || plugged == BatteryManager.BATTERY_PLUGGED_USB;
+                    || plugged == BatteryManager.BATTERY_PLUGGED_USB
+                    || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
         }
 
         /**
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
index fb6ff24..d521c05 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -123,8 +123,7 @@
             if (!mNeedsInput) {
                 flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
             }
-            if (ActivityManager.isHighEndGfx(((WindowManager)mContext.getSystemService(
-                    Context.WINDOW_SERVICE)).getDefaultDisplay())) {
+            if (ActivityManager.isHighEndGfx()) {
                 flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
             }
             WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
@@ -132,8 +131,7 @@
                     flags, PixelFormat.TRANSLUCENT);
             lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
             lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen;
-            if (ActivityManager.isHighEndGfx(((WindowManager)mContext.getSystemService(
-                    Context.WINDOW_SERVICE)).getDefaultDisplay())) {
+            if (ActivityManager.isHighEndGfx()) {
                 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
                 lp.privateFlags |=
                         WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 1fb63db..4d05a87 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -33,7 +33,7 @@
 import android.media.AudioManager;
 import android.media.SoundPool;
 import android.os.Handler;
-import android.os.LocalPowerManager;
+import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.RemoteException;
@@ -44,7 +44,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.view.KeyEvent;
-import android.view.WindowManagerImpl;
+import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
 
 
@@ -156,10 +156,6 @@
     private boolean mSuppressNextLockSound = true;
 
 
-    /** Low level access to the power manager for enableUserActivity.  Having this
-     * requires that we run in the system process.  */
-    LocalPowerManager mRealPowerManager;
-
     /** High level access to the power manager for WakeLocks */
     private PowerManager mPM;
 
@@ -228,7 +224,7 @@
 
     private KeyguardUpdateMonitor mUpdateMonitor;
 
-    private boolean mScreenOn = false;
+    private boolean mScreenOn;
 
     // last known state of the cellular connection
     private String mPhoneState = TelephonyManager.EXTRA_STATE_IDLE;
@@ -357,11 +353,9 @@
 
     };
 
-    public KeyguardViewMediator(Context context, PhoneWindowManager callback,
-            LocalPowerManager powerManager) {
+    public KeyguardViewMediator(Context context, PhoneWindowManager callback) {
         mContext = context;
         mCallback = callback;
-        mRealPowerManager = powerManager;
         mPM = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mWakeLock = mPM.newWakeLock(
                 PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "keyguard");
@@ -382,9 +376,9 @@
         mKeyguardViewProperties
                 = new LockPatternKeyguardViewProperties(mLockPatternUtils, mUpdateMonitor);
 
+        WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
         mKeyguardViewManager = new KeyguardViewManager(
-                context, WindowManagerImpl.getDefault(), this,
-                mKeyguardViewProperties, mUpdateMonitor);
+                context, wm, this, mKeyguardViewProperties, mUpdateMonitor);
 
         mUserPresentIntent = new Intent(Intent.ACTION_USER_PRESENT);
         mUserPresentIntent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
@@ -393,6 +387,8 @@
         final ContentResolver cr = mContext.getContentResolver();
         mShowLockIcon = (Settings.System.getInt(cr, "show_status_bar_lock", 0) == 1);
 
+        mScreenOn = mPM.isScreenOn();
+
         mLockSounds = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
         String soundPath = Settings.System.getString(cr, Settings.System.LOCK_SOUND);
         if (soundPath != null) {
@@ -974,7 +970,7 @@
      * interacts with the keyguard ui should be posted to this handler, rather
      * than called directly.
      */
-    private Handler mHandler = new Handler() {
+    private Handler mHandler = new Handler(Looper.myLooper(), null, true /*async*/) {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -1031,7 +1027,7 @@
         if (DEBUG) Log.d(TAG, "handleKeyguardDone");
         handleHide();
         if (wakeup) {
-            mPM.userActivity(SystemClock.uptimeMillis(), true);
+            mPM.wakeUp(SystemClock.uptimeMillis());
         }
         mWakeLock.release();
         mContext.sendBroadcast(mUserPresentIntent);
@@ -1164,7 +1160,8 @@
         // disable user activity if we are shown and not hidden
         if (DEBUG) Log.d(TAG, "adjustUserActivityLocked mShowing: " + mShowing + " mHidden: " + mHidden);
         boolean enabled = !mShowing || mHidden;
-        mRealPowerManager.enableUserActivity(enabled);
+        // FIXME: Replace this with a new timeout control mechanism.
+        //mRealPowerManager.enableUserActivity(enabled);
         if (!enabled && mScreenOn) {
             // reinstate our short screen timeout policy
             pokeWakelock();
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 82181d3..91b5ca1 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -32,6 +32,7 @@
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.os.UserHandle;
 import android.os.Vibrator;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -275,7 +276,8 @@
 
             // Update the search icon with drawable from the search .apk
             if (!mSearchDisabled) {
-                Intent intent = SearchManager.getAssistIntent(mContext);
+                Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+                        .getAssistIntent(mContext, UserHandle.USER_CURRENT);
                 if (intent != null) {
                     // XXX Hack. We need to substitute the icon here but haven't formalized
                     // the public API. The "_google" metadata will be going away, so
@@ -309,7 +311,9 @@
             final int resId = mGlowPadView.getResourceIdForTarget(target);
             switch (resId) {
                 case com.android.internal.R.drawable.ic_action_assist_generic:
-                    Intent assistIntent = SearchManager.getAssistIntent(mContext);
+                    Intent assistIntent =
+                            ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+                            .getAssistIntent(mContext, UserHandle.USER_CURRENT);
                     if (assistIntent != null) {
                         launchActivity(assistIntent);
                     } else {
@@ -335,6 +339,10 @@
             }
         }
 
+        /**
+         * Launches the said intent for the current foreground user.
+         * @param intent
+         */
         private void launchActivity(Intent intent) {
             intent.setFlags(
                     Intent.FLAG_ACTIVITY_NEW_TASK
@@ -346,7 +354,7 @@
                 Log.w(TAG, "can't dismiss keyguard on launch");
             }
             try {
-                mContext.startActivity(intent);
+                mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
             } catch (ActivityNotFoundException e) {
                 Log.w(TAG, "Activity not found for intent + " + intent.getAction());
             }
@@ -522,7 +530,9 @@
         } else if (disabledBySimState) {
             Log.v(TAG, "Camera disabled by Sim State");
         }
-        boolean searchActionAvailable = SearchManager.getAssistIntent(mContext) != null;
+        boolean searchActionAvailable =
+                ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+                .getAssistIntent(mContext, UserHandle.USER_CURRENT) != null;
         mCameraDisabled = disabledByAdmin || disabledBySimState || !cameraTargetPresent;
         mSearchDisabled = disabledBySimState || !searchActionAvailable || !searchTargetPresent;
         mUnlockWidgetMethods.updateResources();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 8c627a3..209ad38 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -42,10 +42,10 @@
 import android.media.IAudioService;
 import android.os.BatteryManager;
 import android.os.Bundle;
+import android.os.FactoryTest;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
-import android.os.LocalPowerManager;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
@@ -55,6 +55,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UEventObserver;
+import android.os.UserHandle;
 import android.os.Vibrator;
 import android.provider.Settings;
 
@@ -82,6 +83,7 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.WindowManagerGlobal;
 import android.view.WindowOrientationListener;
 import android.view.Surface;
 import android.view.View;
@@ -132,7 +134,6 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import android.view.WindowManagerImpl;
 import android.view.WindowManagerPolicy;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
 import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
@@ -169,12 +170,10 @@
     static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true;
     static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
 
-    // Should screen savers use their own timeout, or the SCREEN_OFF_TIMEOUT?
-    static final boolean SEPARATE_TIMEOUT_FOR_SCREEN_SAVER = 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;
+    static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3;
 
     // These need to match the documentation/constant in
     // core/res/res/values/config.xml
@@ -279,7 +278,7 @@
     Context mContext;
     IWindowManager mWindowManager;
     WindowManagerFuncs mWindowManagerFuncs;
-    LocalPowerManager mPowerManager;
+    PowerManager mPowerManager;
     IStatusBarService mStatusBarService;
     final Object mServiceAquireLock = new Object();
     Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
@@ -473,13 +472,6 @@
     int mLockScreenTimeout;
     boolean mLockScreenTimerActive;
 
-    // visual screen saver support
-    boolean mScreenSaverFeatureAvailable;
-    int mScreenSaverTimeout = 0;
-    boolean mScreenSaverEnabledByUser = false;
-    boolean mScreenSaverMayRun = true; // false if a wakelock is held
-    boolean mPluggedIn;
-
     // Behavior of ENDCALL Button.  (See Settings.System.END_BUTTON_BEHAVIOR.)
     int mEndcallBehavior;
 
@@ -571,12 +563,6 @@
                     Settings.Secure.DEFAULT_INPUT_METHOD), false, this);
             resolver.registerContentObserver(Settings.System.getUriFor(
                     "fancy_rotation_anim"), false, this);
-            resolver.registerContentObserver(Settings.Secure.getUriFor(
-                    Settings.Secure.SCREENSAVER_ENABLED), false, this);
-            if (SEPARATE_TIMEOUT_FOR_SCREEN_SAVER) {
-                resolver.registerContentObserver(Settings.Secure.getUriFor(
-                        "screensaver_timeout"), false, this);
-            } // otherwise SCREEN_OFF_TIMEOUT will do nicely
             updateSettings();
         }
 
@@ -732,8 +718,12 @@
         public void run() {
             // The context isn't read
             if (mLongPressOnPowerBehavior < 0) {
-                mLongPressOnPowerBehavior = mContext.getResources().getInteger(
-                        com.android.internal.R.integer.config_longPressOnPowerBehavior);
+                if (FactoryTest.isLongPressOnPowerOffEnabled()) {
+                    mLongPressOnPowerBehavior = LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
+                } else {
+                    mLongPressOnPowerBehavior = mContext.getResources().getInteger(
+                            com.android.internal.R.integer.config_longPressOnPowerBehavior);
+                }
             }
             switch (mLongPressOnPowerBehavior) {
             case LONG_PRESS_POWER_NOTHING:
@@ -745,10 +735,12 @@
                 showGlobalActionsDialog();
                 break;
             case LONG_PRESS_POWER_SHUT_OFF:
+            case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
                 mPowerKeyHandled = true;
                 performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
                 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
-                mWindowManagerFuncs.shutdown();
+                mWindowManagerFuncs.shutdown(
+                        mLongPressOnPowerBehavior == LONG_PRESS_POWER_SHUT_OFF);
                 break;
             }
         }
@@ -862,16 +854,14 @@
 
     /** {@inheritDoc} */
     public void init(Context context, IWindowManager windowManager,
-            WindowManagerFuncs windowManagerFuncs,
-            LocalPowerManager powerManager) {
+            WindowManagerFuncs windowManagerFuncs) {
         mContext = context;
         mWindowManager = windowManager;
         mWindowManagerFuncs = windowManagerFuncs;
-        mPowerManager = powerManager;
         mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
         if (!mHeadless) {
             // don't create KeyguardViewMediator if headless
-            mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager);
+            mKeyguardMediator = new KeyguardViewMediator(context, this);
         }
         mHandler = new PolicyHandler();
         mOrientationListener = new MyOrientationListener(mContext);
@@ -897,8 +887,8 @@
         mDeskDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
 
-        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                 "PhoneWindowManager.mBroadcastWakeLock");
         mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
         mLidOpenRotation = readRotation(
@@ -931,14 +921,6 @@
                     Intent.EXTRA_DOCK_STATE_UNDOCKED);
         }
 
-        // watch the plug to know whether to trigger the screen saver
-        filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-        intent = context.registerReceiver(mPowerReceiver, filter);
-        if (intent != null) {
-            mPluggedIn = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
-        }
-
         mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
         mLongPressVibePattern = getLongIntArray(mContext.getResources(),
                 com.android.internal.R.array.config_longPressVibePattern);
@@ -1120,26 +1102,6 @@
                 mHasSoftInput = hasSoftInput;
                 updateRotation = true;
             }
-
-            // dreams
-            mScreenSaverFeatureAvailable = mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_enableDreams);
-            
-            mScreenSaverEnabledByUser = 0 != Settings.Secure.getInt(resolver,
-                    Settings.Secure.SCREENSAVER_ENABLED, 0);
-
-            if (SEPARATE_TIMEOUT_FOR_SCREEN_SAVER) {
-                mScreenSaverTimeout = Settings.Secure.getInt(resolver,
-                        "screensaver_timeout", 0);
-            } else {
-                mScreenSaverTimeout = Settings.System.getInt(resolver,
-                        Settings.System.SCREEN_OFF_TIMEOUT, 0);
-                if (mScreenSaverTimeout > 0) {
-                    // We actually want to activate the screensaver just before the
-                    // power manager's screen timeout
-                    mScreenSaverTimeout -= 5000;
-                }
-            }
         }
         if (updateRotation) {
             updateRotation(true);
@@ -1218,7 +1180,7 @@
         
         if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
                 || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) {
-            return WindowManagerImpl.ADD_OKAY;
+            return WindowManagerGlobal.ADD_OKAY;
         }
         String permission = null;
         switch (type) {
@@ -1245,10 +1207,10 @@
         if (permission != null) {
             if (mContext.checkCallingOrSelfPermission(permission)
                     != PackageManager.PERMISSION_GRANTED) {
-                return WindowManagerImpl.ADD_PERMISSION_DENIED;
+                return WindowManagerGlobal.ADD_PERMISSION_DENIED;
             }
         }
-        return WindowManagerImpl.ADD_OKAY;
+        return WindowManagerGlobal.ADD_OKAY;
     }
     
     public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
@@ -1545,7 +1507,7 @@
             // Only return the view if it was successfully added to the
             // window manager... which we can tell by it having a parent.
             return view.getParent() != null ? view : null;
-        } catch (WindowManagerImpl.BadTokenException e) {
+        } catch (WindowManager.BadTokenException e) {
             // ignore
             Log.w(TAG, appToken + " already running, starting window not displayed");
         } catch (RuntimeException e) {
@@ -1584,7 +1546,8 @@
      * @param win The window to be added
      * @param attrs Information about the window to be added
      * 
-     * @return If ok, WindowManagerImpl.ADD_OKAY.  If too many singletons, WindowManagerImpl.ADD_MULTIPLE_SINGLETON
+     * @return If ok, WindowManagerImpl.ADD_OKAY.  If too many singletons,
+     * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
      */
     public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
         switch (attrs.type) {
@@ -1594,7 +1557,7 @@
                         "PhoneWindowManager");
                 if (mStatusBar != null) {
                     if (mStatusBar.isAlive()) {
-                        return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
+                        return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
                     }
                 }
                 mStatusBar = win;
@@ -1605,7 +1568,7 @@
                         "PhoneWindowManager");
                 if (mNavigationBar != null) {
                     if (mNavigationBar.isAlive()) {
-                        return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
+                        return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
                     }
                 }
                 mNavigationBar = win;
@@ -1628,12 +1591,12 @@
                 break;
             case TYPE_KEYGUARD:
                 if (mKeyguard != null) {
-                    return WindowManagerImpl.ADD_MULTIPLE_SINGLETON;
+                    return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
                 }
                 mKeyguard = win;
                 break;
         }
-        return WindowManagerImpl.ADD_OKAY;
+        return WindowManagerGlobal.ADD_OKAY;
     }
 
     /** {@inheritDoc} */
@@ -1763,15 +1726,17 @@
                 mHomePressed = false;
                 mHomeLongPressed = false;
                 if (!homeWasLongPressed) {
-                    try {
-                        IStatusBarService statusbar = getStatusBarService();
-                        if (statusbar != null) {
-                            statusbar.cancelPreloadRecentApps();
+                    if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
+                        try {
+                            IStatusBarService statusbar = getStatusBarService();
+                            if (statusbar != null) {
+                                statusbar.cancelPreloadRecentApps();
+                            }
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "RemoteException when showing recent apps", e);
+                            // re-acquire status bar service next time it is needed.
+                            mStatusBarService = null;
                         }
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "RemoteException when showing recent apps", e);
-                        // re-acquire status bar service next time it is needed.
-                        mStatusBarService = null;
                     }
 
                     mHomePressed = false;
@@ -2110,7 +2075,7 @@
             if (searchManager != null) {
                 searchManager.stopSearch();
             }
-            mContext.startActivity(intent);
+            mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
         } catch (ActivityNotFoundException e) {
             Slog.w(TAG, "No activity to handle assist long press action.", e);
         }
@@ -2118,13 +2083,14 @@
 
     private void launchAssistAction() {
         sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
-        Intent intent = SearchManager.getAssistIntent(mContext);
+        Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+                .getAssistIntent(mContext, UserHandle.USER_CURRENT);
         if (intent != null) {
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                     | Intent.FLAG_ACTIVITY_SINGLE_TOP
                     | Intent.FLAG_ACTIVITY_CLEAR_TOP);
             try {
-                mContext.startActivity(intent);
+                mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
             } catch (ActivityNotFoundException e) {
                 Slog.w(TAG, "No activity to handle assist action.", e);
             }
@@ -3016,12 +2982,10 @@
                 mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(
                         KeyEvent.KEYCODE_POWER, mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED);
             } else {
-                mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
-                        PowerManager.USER_ACTIVITY_EVENT_BUTTON);
+                mPowerManager.wakeUp(SystemClock.uptimeMillis());
             }
         } else if (!mLidControlsSleep) {
-            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
-                    PowerManager.USER_ACTIVITY_EVENT_OTHER);
+            mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
         }
     }
 
@@ -3180,6 +3144,11 @@
     /** {@inheritDoc} */
     @Override
     public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
+        if (!mSystemBooted) {
+            // If we have not yet booted, don't let key events do anything.
+            return 0;
+        }
+
         final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
         final boolean canceled = event.isCanceled();
         final int keyCode = event.getKeyCode();
@@ -3195,14 +3164,17 @@
                                                 mKeyguardMediator.isShowingAndNotHidden() :
                                                 mKeyguardMediator.isShowing()));
 
-        if (!mSystemBooted) {
-            // If we have not yet booted, don't let key events do anything.
-            return 0;
+        if (keyCode == KeyEvent.KEYCODE_POWER) {
+            policyFlags |= WindowManagerPolicy.FLAG_WAKE;
         }
+        final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
+                | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
 
         if (DEBUG_INPUT) {
             Log.d(TAG, "interceptKeyTq keycode=" + keyCode
-                  + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
+                    + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive
+                    + " policyFlags=" + Integer.toHexString(policyFlags)
+                    + " isWakeKey=" + isWakeKey);
         }
 
         if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
@@ -3210,12 +3182,6 @@
             performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
         }
 
-        if (keyCode == KeyEvent.KEYCODE_POWER) {
-            policyFlags |= WindowManagerPolicy.FLAG_WAKE;
-        }
-        final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
-                | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
-
         // Basic policy based on screen state and keyguard.
         // FIXME: This policy isn't quite correct.  We shouldn't care whether the screen
         //        is on or off, really.  We should care about whether the device is in an
@@ -3239,7 +3205,7 @@
                             mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED);
                 } else {
                     // Otherwise, wake the device ourselves.
-                    result |= ACTION_POKE_USER_ACTIVITY;
+                    result |= ACTION_WAKE_UP;
                 }
             }
         }
@@ -3344,7 +3310,7 @@
                         }
                         if ((mEndcallBehavior
                                 & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
-                            result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
+                            result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
                         }
                     }
                 }
@@ -3386,7 +3352,7 @@
                     mPowerKeyTriggered = false;
                     cancelPendingScreenshotChordAction();
                     if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {
-                        result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
+                        result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
                     }
                     mPendingPowerKeyUpCanceled = false;
                 }
@@ -3471,7 +3437,7 @@
                 mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq();
             } else {
                 // Otherwise, wake the device ourselves.
-                result |= ACTION_POKE_USER_ACTIVITY;
+                result |= ACTION_WAKE_UP;
             }
         }
         return result;
@@ -3551,15 +3517,6 @@
         }
     };
 
-    BroadcastReceiver mPowerReceiver = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
-                mPluggedIn = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
-                if (localLOGV) Log.v(TAG, "BATTERY_CHANGED: " + intent + " plugged=" + mPluggedIn);
-            }
-        }
-    };
-
     /** {@inheritDoc} */
     public void screenTurnedOff(int why) {
         EventLog.writeEvent(70000, 0);
@@ -4033,62 +3990,6 @@
         }
     }
 
-    private IDreamManager getDreamManager() {
-        if (!mScreenSaverFeatureAvailable) {
-            return null;
-        }
-        
-        IDreamManager sandman = IDreamManager.Stub.asInterface(
-                ServiceManager.checkService("dreams"));
-        if (sandman == null) {
-            Log.w(TAG, "Unable to find IDreamManager");
-        }
-        return sandman;
-    }
-
-    @Override
-    public boolean isScreenSaverEnabled() {
-        return (mScreenSaverFeatureAvailable && mScreenSaverEnabledByUser
-                && mScreenSaverMayRun && mScreenOnEarly && mPluggedIn);
-    }
-
-    @Override
-    public boolean startScreenSaver() {
-        synchronized (mLock) {
-            if (isScreenSaverEnabled()) {
-                IDreamManager dm = getDreamManager();
-                if (dm == null) return false;
-                
-                try {
-                    if (localLOGV) Log.v(TAG, "startScreenSaver: entering dreamland...");
-
-                    dm.dream();
-                    return true;
-                } catch (RemoteException ex) {
-                    // too bad, so sad, oh mom, oh dad
-                }
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public void stopScreenSaver() {
-        synchronized (mLock) {
-            IDreamManager dm = getDreamManager();
-            if (dm == null) return;
-            
-            try {
-                if (!dm.isDreaming()) return;
-
-                if (localLOGV) Log.v(TAG, "stopScreenSaver: awakening...");
-                
-                dm.awaken();
-            } catch (RemoteException ex) {
-            }
-        }
-    }
-
     Runnable mScreenLockTimeout = new Runnable() {
         public void run() {
             synchronized (this) {
@@ -4132,8 +4033,6 @@
     }
 
     private void applyLidSwitchState() {
-        mPowerManager.setKeyboardVisibility(isBuiltInKeyboardVisible());
-
         if (mLidState == LID_CLOSED && mLidControlsSleep) {
             mPowerManager.goToSleep(SystemClock.uptimeMillis());
         }
@@ -4315,24 +4214,13 @@
     }
     
     public void screenOnStartedLw() {
-        // The window manager has just grabbed a wake lock. This is our cue to disable the screen
-        // saver.
-        synchronized (mLock) {
-            mScreenSaverMayRun = false;
-        }
     }
 
     public void screenOnStoppedLw() {
         if (mPowerManager.isScreenOn()) {
             if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) {
                 long curTime = SystemClock.uptimeMillis();
-                mPowerManager.userActivity(curTime, false, PowerManager.USER_ACTIVITY_EVENT_OTHER);
-            }
-
-            synchronized (mLock) {
-                // even if the keyguard is up, now that all the wakelocks have been released, we
-                // should re-enable the screen saver
-                mScreenSaverMayRun = true;
+                mPowerManager.userActivity(curTime, false);
             }
         }
     }
diff --git a/preloaded-classes b/preloaded-classes
index c29ba15..feddbd6 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -38,10 +38,6 @@
 android.animation.TypeEvaluator
 android.animation.ValueAnimator
 android.animation.ValueAnimator$1
-android.animation.ValueAnimator$2
-android.animation.ValueAnimator$3
-android.animation.ValueAnimator$4
-android.animation.ValueAnimator$5
 android.animation.ValueAnimator$AnimationHandler
 android.app.ActionBar
 android.app.ActionBar$LayoutParams
@@ -279,7 +275,6 @@
 android.content.res.ObbInfo$1
 android.content.res.ObbScanner
 android.content.res.Resources
-android.content.res.Resources$1
 android.content.res.Resources$Theme
 android.content.res.StringBlock
 android.content.res.StringBlock$StyleIDs
@@ -318,13 +313,11 @@
 android.database.Observable
 android.database.sqlite.DatabaseObjectNotClosedException
 android.database.sqlite.SQLiteClosable
-android.database.sqlite.SQLiteCompiledSql
 android.database.sqlite.SQLiteCursor
 android.database.sqlite.SQLiteCursorDriver
 android.database.sqlite.SQLiteDatabase
 android.database.sqlite.SQLiteDatabase$1
 android.database.sqlite.SQLiteDatabase$CustomFunction
-android.database.sqlite.SQLiteDatabase$DatabaseReentrantLock
 android.database.sqlite.SQLiteDebug
 android.database.sqlite.SQLiteDebug$PagerStats
 android.database.sqlite.SQLiteDirectCursorDriver
@@ -482,7 +475,6 @@
 android.media.AudioFormat
 android.media.AudioManager
 android.media.AudioManager$1
-android.media.AudioManager$2
 android.media.AudioManager$FocusEventHandlerDelegate
 android.media.AudioManager$FocusEventHandlerDelegate$1
 android.media.AudioRecord
@@ -495,8 +487,6 @@
 android.media.IAudioService
 android.media.IAudioService$Stub
 android.media.IAudioService$Stub$Proxy
-android.media.IRemoteControlClientDispatcher
-android.media.IRemoteControlClientDispatcher$Stub
 android.media.JetPlayer
 android.media.MediaFile
 android.media.MediaPlayer
@@ -605,7 +595,6 @@
 android.os.Parcelable$Creator
 android.os.PatternMatcher
 android.os.PatternMatcher$1
-android.os.Power
 android.os.PowerManager
 android.os.PowerManager$WakeLock
 android.os.PowerManager$WakeLock$1
@@ -698,7 +687,6 @@
 android.text.TextDirectionHeuristics
 android.text.TextDirectionHeuristics$1
 android.text.TextDirectionHeuristics$AnyStrong
-android.text.TextDirectionHeuristics$CharCount
 android.text.TextDirectionHeuristics$FirstStrong
 android.text.TextDirectionHeuristics$TextDirectionAlgorithm
 android.text.TextDirectionHeuristics$TextDirectionHeuristicImpl
@@ -729,7 +717,6 @@
 android.text.method.TransformationMethod
 android.text.method.TransformationMethod2
 android.text.method.WordIterator
-android.text.method.WordIterator$1
 android.text.style.AlignmentSpan
 android.text.style.CharacterStyle
 android.text.style.LeadingMarginSpan
@@ -824,10 +811,9 @@
 android.view.InputEvent$1
 android.view.InputEventConsistencyVerifier
 android.view.InputEventConsistencyVerifier$KeyState
-android.view.InputHandler
+android.view.InputEventReceiver
 android.view.InputQueue
 android.view.InputQueue$Callback
-android.view.InputQueue$FinishedCallback
 android.view.KeyCharacterMap
 android.view.KeyCharacterMap$FallbackAction
 android.view.KeyEvent
@@ -903,7 +889,6 @@
 android.view.ViewParent
 android.view.ViewRootImpl
 android.view.ViewRootImpl$2
-android.view.ViewRootImpl$3
 android.view.ViewRootImpl$AccessibilityInteractionConnectionManager
 android.view.ViewRootImpl$InputMethodCallback
 android.view.ViewRootImpl$ResizedInfo
@@ -1005,8 +990,11 @@
 android.widget.CursorAdapter
 android.widget.CursorFilter$CursorFilterClient
 android.widget.EdgeEffect
-android.widget.EdgeGlow
 android.widget.EditText
+android.widget.Editor$Blink
+android.widget.Editor$EasyEditSpanController
+android.widget.Editor$InputContentType
+android.widget.Editor$InputMethodState
 android.widget.ExpandableListView
 android.widget.FastScroller
 android.widget.FastScroller$1
@@ -1080,17 +1068,12 @@
 android.widget.TextView
 android.widget.TextView$2
 android.widget.TextView$3
-android.widget.TextView$Blink
 android.widget.TextView$BufferType
 android.widget.TextView$ChangeWatcher
 android.widget.TextView$CharWrapper
 android.widget.TextView$Drawables
-android.widget.TextView$EasyEditSpanController
-android.widget.TextView$InputContentType
-android.widget.TextView$InputMethodState
 android.widget.TextView$OnEditorActionListener
 android.widget.TextView$SavedState
-android.widget.TextView$TextAlign
 android.widget.VideoView
 android.widget.ViewAnimator
 com.android.i18n.phonenumbers.AsYouTypeFormatter
@@ -1144,7 +1127,7 @@
 com.android.internal.telephony.ITelephonyRegistry
 com.android.internal.telephony.ITelephonyRegistry$Stub
 com.android.internal.telephony.ITelephonyRegistry$Stub$Proxy
-com.android.internal.telephony.Phone$State
+com.android.internal.telephony.PhoneConstants$State
 com.android.internal.util.ArrayUtils
 com.android.internal.util.FastXmlSerializer
 com.android.internal.util.Preconditions
diff --git a/services/common_time/common_time_server.cpp b/services/common_time/common_time_server.cpp
index 17f99b9..21e706f 100644
--- a/services/common_time/common_time_server.cpp
+++ b/services/common_time/common_time_server.cpp
@@ -53,9 +53,9 @@
 
 namespace android {
 
-const char*    CommonTimeServer::kDefaultMasterElectionAddr = "239.195.128.88";
-const uint16_t CommonTimeServer::kDefaultMasterElectionPort = 8887;
-const uint64_t CommonTimeServer::kDefaultSyncGroupID = 0;
+const char*    CommonTimeServer::kDefaultMasterElectionAddr = "255.255.255.255";
+const uint16_t CommonTimeServer::kDefaultMasterElectionPort = 8886;
+const uint64_t CommonTimeServer::kDefaultSyncGroupID = 1;
 const uint8_t  CommonTimeServer::kDefaultMasterPriority = 1;
 const uint32_t CommonTimeServer::kDefaultMasterAnnounceIntervalMs = 10000;
 const uint32_t CommonTimeServer::kDefaultSyncRequestIntervalMs = 1000;
@@ -752,6 +752,9 @@
 bool CommonTimeServer::handleWhoIsMasterRequest(
         const WhoIsMasterRequestPacket* request,
         const sockaddr_storage& srcAddr) {
+    // Skip our own messages which come back via broadcast loopback.
+    if (request->senderDeviceID == mDeviceID)
+        return true;
 
     char srcEPStr[64];
     sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr));
@@ -829,6 +832,10 @@
 bool CommonTimeServer::handleWhoIsMasterResponse(
         const WhoIsMasterResponsePacket* response,
         const sockaddr_storage& srcAddr) {
+    // Skip our own messages which come back via broadcast loopback.
+    if (response->deviceID == mDeviceID)
+        return true;
+
     char srcEPStr[64];
     sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr));
     mElectionLog.log("RXed WhoIs master response while in state %s.  "
@@ -996,6 +1003,10 @@
     uint8_t  newDevicePrio = packet->devicePriority;
     uint64_t newTimelineID = packet->timelineID;
 
+    // Skip our own messages which come back via broadcast loopback.
+    if (newDeviceID == mDeviceID)
+        return true;
+
     char srcEPStr[64];
     sockaddrToString(srcAddr, true, srcEPStr, sizeof(srcEPStr));
     mElectionLog.log("RXed master announcement while in state %s.  "
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 38f4554..8e341df 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -177,7 +177,7 @@
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                onUserRemoved(intent.getIntExtra(Intent.EXTRA_USERID, -1));
+                onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
             }
         }, userFilter);
     }
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 48f967c..539e561 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -43,7 +43,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.AtomicFile;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -499,7 +499,7 @@
                 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
                 intent.setComponent(p.info.provider);
                 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId);
-                mContext.sendBroadcastToUser(intent, mUserId);
+                mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId));
                 if (p.instances.size() == 0) {
                     // cancel the future updates
                     cancelBroadcasts(p);
@@ -507,7 +507,7 @@
                     // send the broacast saying that the provider is not in use any more
                     intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
                     intent.setComponent(p.info.provider);
-                    mContext.sendBroadcastToUser(intent, mUserId);
+                    mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId));
                 }
             }
         }
@@ -593,7 +593,7 @@
     private boolean callerHasBindAppWidgetPermission(String packageName) {
         int callingUid = Binder.getCallingUid();
         try {
-            if (!UserId.isSameApp(callingUid, getUidForPackage(packageName))) {
+            if (!UserHandle.isSameApp(callingUid, getUidForPackage(packageName))) {
                 return false;
             }
         } catch (Exception e) {
@@ -665,7 +665,7 @@
                 mBoundRemoteViewsServices.remove(key);
             }
 
-            int userId = UserId.getUserId(id.provider.uid);
+            int userId = UserHandle.getUserId(id.provider.uid);
             // Bind to the RemoteViewsService (which will trigger a callback to the
             // RemoteViewsAdapter.onServiceConnected())
             final long token = Binder.clearCallingIdentity();
@@ -756,7 +756,7 @@
             }
         };
 
-        int userId = UserId.getUserId(id.provider.uid);
+        int userId = UserHandle.getUserId(id.provider.uid);
         // Bind to the service and remove the static intent->factory mapping in the
         // RemoteViewsService.
         final long token = Binder.clearCallingIdentity();
@@ -880,7 +880,7 @@
             intent.setComponent(p.info.provider);
             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId);
             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
-            mContext.sendBroadcastToUser(intent, mUserId);
+            mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId));
         }
     }
 
@@ -1026,7 +1026,7 @@
                             }
                         };
 
-                        int userId = UserId.getUserId(id.provider.uid);
+                        int userId = UserHandle.getUserId(id.provider.uid);
                         // Bind to the service and call onDataSetChanged()
                         final long token = Binder.clearCallingIdentity();
                         try {
@@ -1205,7 +1205,7 @@
     void sendEnableIntentLocked(Provider p) {
         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
         intent.setComponent(p.info.provider);
-        mContext.sendBroadcastToUser(intent, mUserId);
+        mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId));
     }
 
     void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) {
@@ -1213,7 +1213,7 @@
             Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
             intent.setComponent(p.info.provider);
-            mContext.sendBroadcastToUser(intent, mUserId);
+            mContext.sendBroadcastAsUser(intent, new UserHandle(mUserId));
         }
     }
 
@@ -1375,7 +1375,7 @@
             throw new IllegalArgumentException("packageName and uid don't match packageName="
                     + packageName);
         }
-        if (!UserId.isSameApp(callingUid, packageUid)) {
+        if (!UserHandle.isSameApp(callingUid, packageUid)) {
             throw new IllegalArgumentException("packageName and uid don't match packageName="
                     + packageName);
         }
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 2167c49..8be0ba8 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -65,6 +65,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.UserHandle;
 import android.os.WorkSource;
 import android.os.storage.IMountService;
 import android.provider.Settings;
@@ -4845,6 +4846,18 @@
     // ----- IBackupManager binder interface -----
 
     public void dataChanged(final String packageName) {
+        final int callingUserHandle = UserHandle.getCallingUserId();
+        if (callingUserHandle != UserHandle.USER_OWNER) {
+            // App is running under a non-owner user profile.  For now, we do not back
+            // up data from secondary user profiles.
+            // TODO: backups for all user profiles.
+            if (MORE_DEBUG) {
+                Slog.v(TAG, "dataChanged(" + packageName + ") ignored because it's user "
+                        + callingUserHandle);
+            }
+            return;
+        }
+
         final HashSet<String> targets = dataChangedTargets(packageName);
         if (targets == null) {
             Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
@@ -4937,6 +4950,11 @@
             boolean doAllApps, boolean includeSystem, String[] pkgList) {
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullBackup");
 
+        final int callingUserHandle = UserHandle.getCallingUserId();
+        if (callingUserHandle != UserHandle.USER_OWNER) {
+            throw new IllegalStateException("Backup supported only for the device owner");
+        }
+
         // Validate
         if (!doAllApps) {
             if (!includeShared) {
@@ -5001,6 +5019,11 @@
     public void fullRestore(ParcelFileDescriptor fd) {
         mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "fullRestore");
 
+        final int callingUserHandle = UserHandle.getCallingUserId();
+        if (callingUserHandle != UserHandle.USER_OWNER) {
+            throw new IllegalStateException("Restore supported only for the device owner");
+        }
+
         long oldId = Binder.clearCallingIdentity();
 
         try {
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 0a6f23c..6ae16a4 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -93,6 +93,7 @@
 
     private boolean mAcOnline;
     private boolean mUsbOnline;
+    private boolean mWirelessOnline;
     private int mBatteryStatus;
     private int mBatteryHealth;
     private boolean mBatteryPresent;
@@ -150,7 +151,8 @@
 
     public final boolean isPowered() {
         // assume we are powered if battery state is unknown so the "stay on while plugged in" option will work.
-        return (mAcOnline || mUsbOnline || mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN);
+        return (mAcOnline || mUsbOnline || mWirelessOnline
+                || mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN);
     }
 
     public final boolean isPowered(int plugTypeSet) {
@@ -169,6 +171,9 @@
         if (mUsbOnline) {
             plugTypeBit |= BatteryManager.BATTERY_PLUGGED_USB;
         }
+        if (mWirelessOnline) {
+            plugTypeBit |= BatteryManager.BATTERY_PLUGGED_WIRELESS;
+        }
         return (plugTypeSet & plugTypeBit) != 0;
     }
 
@@ -243,6 +248,8 @@
             mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
         } else if (mUsbOnline) {
             mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
+        } else if (mWirelessOnline) {
+            mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
         } else {
             mPlugType = BATTERY_PLUGGED_NONE;
         }
@@ -398,6 +405,7 @@
                     " temperature: " + mBatteryTemperature +
                     " technology: " + mBatteryTechnology +
                     " AC powered:" + mAcOnline + " USB powered:" + mUsbOnline +
+                    " Wireless powered:" + mWirelessOnline +
                     " icon:" + icon  + " invalid charger:" + mInvalidCharger);
         }
 
@@ -503,6 +511,7 @@
                 pw.println("Current Battery Service state:");
                 pw.println("  AC powered: " + mAcOnline);
                 pw.println("  USB powered: " + mUsbOnline);
+                pw.println("  Wireless powered: " + mWirelessOnline);
                 pw.println("  status: " + mBatteryStatus);
                 pw.println("  health: " + mBatteryHealth);
                 pw.println("  present: " + mBatteryPresent);
@@ -523,6 +532,8 @@
                         mAcOnline = Integer.parseInt(value) != 0;
                     } else if ("usb".equals(key)) {
                         mUsbOnline = Integer.parseInt(value) != 0;
+                    } else if ("wireless".equals(key)) {
+                        mWirelessOnline = Integer.parseInt(value) != 0;
                     } else if ("status".equals(key)) {
                         mBatteryStatus = Integer.parseInt(value);
                     } else if ("level".equals(key)) {
@@ -603,4 +614,3 @@
         }
     }
 }
-
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
old mode 100644
new mode 100755
index cc9b9fa..4c98ac3
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -22,6 +22,7 @@
 import android.os.Message;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.Binder;
 import android.provider.Settings;
 import android.util.Log;
 import java.util.List;
@@ -66,6 +67,7 @@
     private IBluetooth mBluetooth;
     private boolean mBinding;
     private boolean mUnbinding;
+    private boolean mQuietEnable = false;
 
     private void registerForAirplaneMode(IntentFilter filter) {
         final ContentResolver resolver = mContext.getContentResolver();
@@ -105,7 +107,7 @@
                 } else {
                     if (isBluetoothPersistedStateOn()) {
                         // enable without persisting the setting
-                        handleEnable(false);
+                        handleEnable(false, false);
                     }
                 }
             }
@@ -269,7 +271,32 @@
         Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
         mHandler.sendMessage(msg);
     }
+    public boolean enableNoAutoConnect()
+    {
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+                                                "Need BLUETOOTH ADMIN permission");
+        if (DBG) {
+            Log.d(TAG,"enableNoAutoConnect():  mBluetooth =" + mBluetooth +
+                    " mBinding = " + mBinding);
+        }
+        if (Binder.getCallingUid() != android.os.Process.NFC_UID) {
+            throw new SecurityException("no permission to enable Bluetooth quietly");
+        }
+        synchronized(mConnection) {
+            if (mBinding) {
+                Log.w(TAG,"enableNoAutoConnect(): binding in progress. Returning..");
+                return true;
+            }
+            if (mConnection == null) mBinding = true;
+        }
 
+        Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
+        msg.arg1=0; //No persist
+        msg.arg2=1; //Quiet mode
+        mHandler.sendMessage(msg);
+        return true;
+
+    }
     public boolean enable() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH ADMIN permission");
@@ -288,6 +315,7 @@
 
         Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
         msg.arg1=1; //persist
+        msg.arg2=0; //No Quiet Mode
         mHandler.sendMessage(msg);
         return true;
     }
@@ -501,7 +529,7 @@
                         Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
                     }
 
-                    handleEnable(msg.arg1 == 1);
+                    handleEnable(msg.arg1 == 1, msg.arg2 ==1);
                     break;
 
                 case MESSAGE_DISABLE:
@@ -574,14 +602,21 @@
 
                         //Do enable request
                         try {
-                            if(!mBluetooth.enable()) {
-                                Log.e(TAG,"IBluetooth.enable() returned false");
+                            if (mQuietEnable == false) {
+                                if(!mBluetooth.enable()) {
+                                    Log.e(TAG,"IBluetooth.enable() returned false");
+                                }
+                            }
+                            else
+                            {
+                                if(!mBluetooth.enableNoAutoConnect()) {
+                                    Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
+                                }
                             }
                         } catch (RemoteException e) {
                             Log.e(TAG,"Unable to call enable()",e);
                         }
                     }
-
                     break;
                 }
                 case MESSAGE_TIMEOUT_BIND: {
@@ -637,11 +672,13 @@
         }
     };
 
-    private void handleEnable(boolean persist) {
+    private void handleEnable(boolean persist, boolean quietMode) {
         if (persist) {
             persistBluetoothSetting(true);
         }
 
+        mQuietEnable = quietMode;
+
         synchronized(mConnection) {
             if (mBluetooth == null) {
                 //Start bind timeout and bind
@@ -664,8 +701,15 @@
 
                 //Enable bluetooth
                 try {
-                    if(!mBluetooth.enable()) {
-                        Log.e(TAG,"IBluetooth.enable() returned false");
+                    if (!mQuietEnable) {
+                        if(!mBluetooth.enable()) {
+                            Log.e(TAG,"IBluetooth.enable() returned false");
+                        }
+                    }
+                    else {
+                        if(!mBluetooth.enableNoAutoConnect()) {
+                            Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
+                        }
                     }
                 } catch (RemoteException e) {
                     Log.e(TAG,"Unable to call enable()",e);
diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java
index 8a6a550..0bf7aad 100644
--- a/services/java/com/android/server/ClipboardService.java
+++ b/services/java/com/android/server/ClipboardService.java
@@ -36,7 +36,7 @@
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -96,7 +96,7 @@
             public void onReceive(Context context, Intent intent) {
                 String action = intent.getAction();
                 if (Intent.ACTION_USER_REMOVED.equals(action)) {
-                    removeClipboard(intent.getIntExtra(Intent.EXTRA_USERID, 0));
+                    removeClipboard(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
                 }
             }
         }, userFilter);
@@ -115,7 +115,7 @@
     }
 
     private PerUserClipboard getClipboard() {
-        return getClipboard(UserId.getCallingUserId());
+        return getClipboard(UserHandle.getCallingUserId());
     }
 
     private PerUserClipboard getClipboard(int userId) {
@@ -258,7 +258,7 @@
         PackageInfo pi;
         try {
             pi = mPm.getPackageInfo(pkg, 0);
-            if (!UserId.isSameApp(pi.applicationInfo.uid, uid)) {
+            if (!UserHandle.isSameApp(pi.applicationInfo.uid, uid)) {
                 throw new SecurityException("Calling uid " + uid
                         + " does not own package " + pkg);
             }
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 375ba68..cb6ce4b 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -2592,6 +2592,11 @@
                     //       @see bug/4455071
                     handleConnectivityChange(info.getType(), false);
                     break;
+                case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
+                    info = (NetworkInfo) msg.obj;
+                    type = info.getType();
+                    updateNetworkSettings(mNetTrackers[type]);
+                    break;
             }
         }
     }
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index ea19d6e..f966a33 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -1626,7 +1626,7 @@
             mLastMaximumTimeToLock = timeMs;
 
             try {
-                getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
+                getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
             } catch (RemoteException e) {
                 Slog.w(TAG, "Failure talking with power manager", e);
             }
@@ -1667,8 +1667,8 @@
             long ident = Binder.clearCallingIdentity();
             try {
                 // Power off the display
-                mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
-                        WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
+                getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
+                        PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
                 // Ensure the device is locked
                 getWindowManager().lockNow();
             } catch (RemoteException e) {
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 6f050d3..ef09b01 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -18,10 +18,6 @@
 
 import static android.provider.Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK;
 
-import com.android.server.power.PowerManagerService;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -30,9 +26,11 @@
 import android.media.RingtoneManager;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.UEventObserver;
 import android.provider.Settings;
@@ -46,7 +44,7 @@
 /**
  * <p>DockObserver monitors for a docking station.
  */
-class DockObserver extends UEventObserver {
+final class DockObserver extends UEventObserver {
     private static final String TAG = DockObserver.class.getSimpleName();
     private static final boolean LOG = false;
 
@@ -55,7 +53,9 @@
 
     private static final int DEFAULT_DOCK = 1;
 
-    private static final int MSG_DOCK_STATE = 0;
+    private static final int MSG_DOCK_STATE_CHANGED = 0;
+
+    private final Object mLock = new Object();
 
     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
     private int mPreviousDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
@@ -64,11 +64,8 @@
 
     private final Context mContext;
 
-    private PowerManagerService mPowerManager;
-
-    public DockObserver(Context context, PowerManagerService pm) {
+    public DockObserver(Context context) {
         mContext = context;
-        mPowerManager = pm;
         init();  // set initial status
 
         startObserving(DOCK_UEVENT_MATCH);
@@ -80,7 +77,7 @@
             Slog.v(TAG, "Dock UEVENT: " + event.toString());
         }
 
-        synchronized (this) {
+        synchronized (mLock) {
             try {
                 int newState = Integer.parseInt(event.get("SWITCH_STATE"));
                 if (newState != mDockState) {
@@ -94,10 +91,11 @@
                                 && mPreviousDockState != Intent.EXTRA_DOCK_STATE_LE_DESK
                                 && mPreviousDockState != Intent.EXTRA_DOCK_STATE_HE_DESK) ||
                                 mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
-                            mPowerManager.userActivityWithForce(SystemClock.uptimeMillis(),
-                                    false, true);
+                            PowerManager pm =
+                                    (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+                            pm.wakeUp(SystemClock.uptimeMillis());
                         }
-                        update();
+                        updateLocked();
                     }
                 }
             } catch (NumberFormatException e) {
@@ -106,132 +104,142 @@
         }
     }
 
-    private final void init() {
-        char[] buffer = new char[1024];
-
-        try {
-            FileReader file = new FileReader(DOCK_STATE_PATH);
-            int len = file.read(buffer, 0, 1024);
-            file.close();
-            mPreviousDockState = mDockState = Integer.valueOf((new String(buffer, 0, len)).trim());
-        } catch (FileNotFoundException e) {
-            Slog.w(TAG, "This kernel does not have dock station support");
-        } catch (Exception e) {
-            Slog.e(TAG, "" , e);
+    private void init() {
+        synchronized (mLock) {
+            try {
+                char[] buffer = new char[1024];
+                FileReader file = new FileReader(DOCK_STATE_PATH);
+                try {
+                    int len = file.read(buffer, 0, 1024);
+                    mDockState = Integer.valueOf((new String(buffer, 0, len)).trim());
+                    mPreviousDockState = mDockState;
+                } finally {
+                    file.close();
+                }
+            } catch (FileNotFoundException e) {
+                Slog.w(TAG, "This kernel does not have dock station support");
+            } catch (Exception e) {
+                Slog.e(TAG, "" , e);
+            }
         }
     }
 
     void systemReady() {
-        synchronized (this) {
+        synchronized (mLock) {
             // don't bother broadcasting undocked here
             if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
-                update();
+                updateLocked();
             }
             mSystemReady = true;
         }
     }
 
-    private final void update() {
-        mHandler.sendEmptyMessage(MSG_DOCK_STATE);
+    private void updateLocked() {
+        mHandler.sendEmptyMessage(MSG_DOCK_STATE_CHANGED);
+    }
+
+    private void handleDockStateChange() {
+        synchronized (mLock) {
+            Slog.i(TAG, "Dock state changed: " + mDockState);
+
+            final ContentResolver cr = mContext.getContentResolver();
+
+            if (Settings.Secure.getInt(cr,
+                    Settings.Secure.DEVICE_PROVISIONED, 0) == 0) {
+                Slog.i(TAG, "Device not provisioned, skipping dock broadcast");
+                return;
+            }
+
+            // Pack up the values and broadcast them to everyone
+            Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
+            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+            intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
+
+            // Check if this is Bluetooth Dock
+            // TODO(BT): Get Dock address.
+            // String address = null;
+            // if (address != null) {
+            //    intent.putExtra(BluetoothDevice.EXTRA_DEVICE,
+            //            BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address));
+            // }
+
+            // User feedback to confirm dock connection. Particularly
+            // useful for flaky contact pins...
+            if (Settings.System.getInt(cr,
+                    Settings.System.DOCK_SOUNDS_ENABLED, 1) == 1) {
+                String whichSound = null;
+                if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+                    if ((mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) ||
+                        (mPreviousDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
+                        (mPreviousDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) {
+                        whichSound = Settings.System.DESK_UNDOCK_SOUND;
+                    } else if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_CAR) {
+                        whichSound = Settings.System.CAR_UNDOCK_SOUND;
+                    }
+                } else {
+                    if ((mDockState == Intent.EXTRA_DOCK_STATE_DESK) ||
+                        (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
+                        (mDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) {
+                        whichSound = Settings.System.DESK_DOCK_SOUND;
+                    } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
+                        whichSound = Settings.System.CAR_DOCK_SOUND;
+                    }
+                }
+
+                if (whichSound != null) {
+                    final String soundPath = Settings.System.getString(cr, whichSound);
+                    if (soundPath != null) {
+                        final Uri soundUri = Uri.parse("file://" + soundPath);
+                        if (soundUri != null) {
+                            final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
+                            if (sfx != null) {
+                                sfx.setStreamType(AudioManager.STREAM_SYSTEM);
+                                sfx.play();
+                            }
+                        }
+                    }
+                }
+            }
+
+            IDreamManager mgr = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams"));
+            if (mgr != null) {
+                // dreams feature enabled
+                boolean undocked = mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED;
+                if (undocked) {
+                    try {
+                        if (mgr.isDreaming()) {
+                            mgr.awaken();
+                        }
+                    } catch (RemoteException e) {
+                        Slog.w(TAG, "Unable to awaken!", e);
+                    }
+                } else {
+                    if (isScreenSaverActivatedOnDock(mContext)) {
+                        try {
+                            mgr.dream();
+                        } catch (RemoteException e) {
+                            Slog.w(TAG, "Unable to dream!", e);
+                        }
+                    }
+                }
+            } else {
+                // dreams feature not enabled, send legacy intent
+                mContext.sendStickyBroadcast(intent);
+            }
+        }
     }
 
     private static boolean isScreenSaverActivatedOnDock(Context context) {
-        return 0 != Settings.Secure.getInt(
-                    context.getContentResolver(), SCREENSAVER_ACTIVATE_ON_DOCK, DEFAULT_DOCK);
+        return Settings.Secure.getInt(context.getContentResolver(),
+                SCREENSAVER_ACTIVATE_ON_DOCK, DEFAULT_DOCK) != 0;
     }
 
-    private final Handler mHandler = new Handler() {
+    private final Handler mHandler = new Handler(Looper.myLooper(), null, true) {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case MSG_DOCK_STATE:
-                    synchronized (this) {
-                        Slog.i(TAG, "Dock state changed: " + mDockState);
-
-                        final ContentResolver cr = mContext.getContentResolver();
-
-                        if (Settings.Secure.getInt(cr,
-                                Settings.Secure.DEVICE_PROVISIONED, 0) == 0) {
-                            Slog.i(TAG, "Device not provisioned, skipping dock broadcast");
-                            return;
-                        }
-                        // Pack up the values and broadcast them to everyone
-                        Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
-                        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
-                        intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
-
-                        // Check if this is Bluetooth Dock
-                        // TODO(BT): Get Dock address.
-                        String address = null;
-                        if (address != null)
-                            intent.putExtra(BluetoothDevice.EXTRA_DEVICE,
-                                    BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address));
-
-                        // User feedback to confirm dock connection. Particularly
-                        // useful for flaky contact pins...
-                        if (Settings.System.getInt(cr,
-                                Settings.System.DOCK_SOUNDS_ENABLED, 1) == 1)
-                        {
-                            String whichSound = null;
-                            if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
-                                if ((mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) ||
-                                    (mPreviousDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
-                                    (mPreviousDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) {
-                                    whichSound = Settings.System.DESK_UNDOCK_SOUND;
-                                } else if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_CAR) {
-                                    whichSound = Settings.System.CAR_UNDOCK_SOUND;
-                                }
-                            } else {
-                                if ((mDockState == Intent.EXTRA_DOCK_STATE_DESK) ||
-                                    (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
-                                    (mDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) {
-                                    whichSound = Settings.System.DESK_DOCK_SOUND;
-                                } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
-                                    whichSound = Settings.System.CAR_DOCK_SOUND;
-                                }
-                            }
-
-                            if (whichSound != null) {
-                                final String soundPath = Settings.System.getString(cr, whichSound);
-                                if (soundPath != null) {
-                                    final Uri soundUri = Uri.parse("file://" + soundPath);
-                                    if (soundUri != null) {
-                                        final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
-                                        if (sfx != null) {
-                                            sfx.setStreamType(AudioManager.STREAM_SYSTEM);
-                                            sfx.play();
-                                        }
-                                    }
-                                }
-                            }
-                        }
-
-                        IDreamManager mgr = IDreamManager.Stub.asInterface(ServiceManager.getService("dreams"));
-                        if (mgr != null) {
-                            // dreams feature enabled
-                            boolean undocked = mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED;
-                            if (undocked) {
-                                try {
-                                    if (mgr.isDreaming()) {
-                                        mgr.awaken();
-                                    }
-                                } catch (RemoteException e) {
-                                    Slog.w(TAG, "Unable to awaken!", e);
-                                }
-                            } else {
-                                if (isScreenSaverActivatedOnDock(mContext)) {
-                                    try {
-                                        mgr.dream();
-                                    } catch (RemoteException e) {
-                                        Slog.w(TAG, "Unable to dream!", e);
-                                    }
-                                }
-                            }
-                        } else {
-                            // dreams feature not enabled, send legacy intent
-                            mContext.sendStickyBroadcast(intent);
-                        }
-                    }
+                case MSG_DOCK_STATE_CHANGED:
+                    handleDockStateChange();
                     break;
             }
         }
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index e219e8d..23b2706 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -47,7 +47,6 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
-import android.os.Parcelable;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
@@ -64,6 +63,8 @@
 import com.android.server.location.GeocoderProxy;
 import com.android.server.location.GeofenceManager;
 import com.android.server.location.GpsLocationProvider;
+import com.android.server.location.LocationBlacklist;
+import com.android.server.location.LocationFudger;
 import com.android.server.location.LocationProviderInterface;
 import com.android.server.location.LocationProviderProxy;
 import com.android.server.location.MockProvider;
@@ -110,19 +111,6 @@
 
     private static final int MSG_LOCATION_CHANGED = 1;
 
-    // Accuracy in meters above which a location is considered coarse
-    private static final double COARSE_ACCURACY_M = 100.0;
-    private static final String EXTRA_COARSE_LOCATION = "coarseLocation";
-
-    private static final int APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR = 111000;
-
-    /**
-     * Maximum latitude of 1 meter from the pole.
-     * This keeps cosine(MAX_LATITUDE) to a non-zero value;
-     */
-    private static final double MAX_LATITUDE =
-            90.0 - (1.0 / APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR);
-
     // Location Providers may sometimes deliver location updates
     // slightly faster that requested - provide grace period so
     // we don't unnecessarily filter events that are otherwise on
@@ -137,6 +125,7 @@
     private final Object mLock = new Object();
 
     // --- fields below are final after init() ---
+    private LocationFudger mLocationFudger;
     private GeofenceManager mGeofenceManager;
     private PowerManager.WakeLock mWakeLock;
     private PackageManager mPackageManager;
@@ -144,8 +133,8 @@
     private IGpsStatusProvider mGpsStatusProvider;
     private INetInitiatedListener mNetInitiatedListener;
     private LocationWorkerHandler mLocationHandler;
-    // track the passive provider for some special cases
-    private PassiveProvider mPassiveProvider;
+    private PassiveProvider mPassiveProvider;  // track passive provider for special cases
+    private LocationBlacklist mBlacklist;
 
     // --- fields below are protected by mWakeLock ---
     private int mPendingBroadcasts;
@@ -220,7 +209,10 @@
         synchronized (mLock) {
             loadProvidersLocked();
         }
-        mGeofenceManager = new GeofenceManager(mContext);
+        mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
+        mBlacklist.init();
+        mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
+        mLocationFudger = new LocationFudger();
 
         // Register for Network (Wifi or Mobile) updates
         IntentFilter filter = new IntentFilter();
@@ -907,7 +899,25 @@
         String perm = checkPermission();
 
         if (ACCESS_COARSE_LOCATION.equals(perm)) {
-            request.applyCoarsePermissionRestrictions();
+             switch (request.getQuality()) {
+                 case LocationRequest.ACCURACY_FINE:
+                     request.setQuality(LocationRequest.ACCURACY_BLOCK);
+                     break;
+                 case LocationRequest.POWER_HIGH:
+                     request.setQuality(LocationRequest.POWER_LOW);
+                     break;
+             }
+             // throttle
+             if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
+                 request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
+             }
+             if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
+                 request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
+             }
+        }
+        // make getFastestInterval() the minimum of interval and fastest interval
+        if (request.getFastestInterval() > request.getInterval()) {
+            request.setFastestInterval(request.getInterval());
         }
         return perm;
     }
@@ -958,7 +968,7 @@
         final int uid = Binder.getCallingUid();
         Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
 
-        // so wakelock calls will succeed (not totally sure this is still needed)
+        // providers may use public location API's, need to clear identity
         long identity = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
@@ -1008,7 +1018,7 @@
         final int uid = Binder.getCallingUid();
         Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
 
-        // so wakelock calls will succeed (not totally sure this is still needed)
+        // providers may use public location API's, need to clear identity
         long identity = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
@@ -1056,10 +1066,17 @@
     }
 
     @Override
-    public Location getLastLocation(LocationRequest request) {
+    public Location getLastLocation(LocationRequest request, String packageName) {
         if (D) Log.d(TAG, "getLastLocation: " + request);
         if (request == null) request = DEFAULT_LOCATION_REQUEST;
         String perm = checkPermissionAndRequest(request);
+        checkPackageName(packageName);
+
+        if (mBlacklist.isBlacklisted(packageName)) {
+            if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
+                    packageName);
+            return null;
+        }
 
         synchronized (mLock) {
             // Figure out the provider. Either its explicitly request (deprecated API's),
@@ -1075,7 +1092,7 @@
             if (ACCESS_FINE_LOCATION.equals(perm)) {
                 return location;
             } else {
-                return getCoarseLocationExtra(location);
+                return mLocationFudger.getOrCreate(location);
             }
         }
     }
@@ -1090,7 +1107,14 @@
 
         if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
 
-        mGeofenceManager.addFence(request, geofence, intent, Binder.getCallingUid(), packageName);
+        // geo-fence manager uses the public location API, need to clear identity
+        int uid = Binder.getCallingUid();
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
     @Override
@@ -1101,7 +1125,13 @@
 
         if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
 
-        mGeofenceManager.removeFence(geofence, intent);
+        // geo-fence manager uses the public location API, need to clear identity
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mGeofenceManager.removeFence(geofence, intent);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
 
@@ -1283,6 +1313,8 @@
     }
 
     private void handleLocationChangedLocked(Location location, boolean passive) {
+        if (D) Log.d(TAG, "incoming location: " + location);
+
         long now = SystemClock.elapsedRealtime();
         String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
         ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
@@ -1291,11 +1323,8 @@
         LocationProviderInterface p = mProvidersByName.get(provider);
         if (p == null) return;
 
-        // Add the coarse location as an extra, if not already present
-        Location coarse = getCoarseLocationExtra(location);
-        if (coarse == null) {
-            coarse = addCoarseLocationExtra(location);
-        }
+        // Add the coarse location as an extra
+        Location coarse = mLocationFudger.getOrCreate(location);
 
         // Update last known locations
         Location lastLocation = mLastLocation.get(provider);
@@ -1319,6 +1348,13 @@
         for (UpdateRecord r : records) {
             Receiver receiver = r.mReceiver;
             boolean receiverDead = false;
+
+            if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
+                if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
+                        receiver.mPackageName);
+                continue;
+            }
+
             if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
                 location = lastLocation;  // use fine location
             } else {
@@ -1530,7 +1566,8 @@
             MockProvider provider = new MockProvider(name, this, properties);
             // remove the real provider if we are replacing GPS or network provider
             if (LocationManager.GPS_PROVIDER.equals(name)
-                    || LocationManager.NETWORK_PROVIDER.equals(name)) {
+                    || LocationManager.NETWORK_PROVIDER.equals(name)
+                    || LocationManager.FUSED_PROVIDER.equals(name)) {
                 LocationProviderInterface p = mProvidersByName.get(name);
                 if (p != null) {
                     removeProviderLocked(p);
@@ -1660,106 +1697,6 @@
         }
     }
 
-    private static double wrapLatitude(double lat) {
-         if (lat > MAX_LATITUDE) lat = MAX_LATITUDE;
-         if (lat < -MAX_LATITUDE) lat = -MAX_LATITUDE;
-         return lat;
-    }
-
-    private static double wrapLongitude(double lon) {
-        if (lon >= 180.0) lon -= 360.0;
-        if (lon < -180.0) lon += 360.0;
-        return lon;
-    }
-
-    private static double distanceToDegreesLatitude(double distance) {
-        return distance / APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR;
-    }
-
-    /**
-     * Requires latitude since longitudinal distances change with distance from equator.
-     */
-    private static double distanceToDegreesLongitude(double distance, double lat) {
-        return distance / APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR / Math.cos(lat);
-    }
-
-    /**
-     * Fudge a location into a coarse location.
-     * <p>Add a random offset, then quantize the result (snap-to-grid).
-     * Random offsets alone can be low-passed pretty easily.
-     * Snap-to-grid on its own is excellent unless you are sitting on a
-     * grid boundary and bouncing between quantizations.
-     * The combination is quite hard to reverse engineer.
-     * <p>The random offset used is smaller than the goal accuracy
-     * ({@link #COARSE_ACCURACY_M}), in order to give relatively stable
-     * results after quantization.
-     */
-    private static Location createCoarse(Location fine) {
-        Location coarse = new Location(fine);
-
-        coarse.removeBearing();
-        coarse.removeSpeed();
-        coarse.removeAltitude();
-
-        double lat = coarse.getLatitude();
-        double lon = coarse.getLongitude();
-
-        // wrap
-        lat = wrapLatitude(lat);
-        lon = wrapLongitude(lon);
-
-        if (coarse.getAccuracy() < COARSE_ACCURACY_M / 2) {
-            // apply a random offset
-            double fudgeDistance = COARSE_ACCURACY_M / 2.0 - coarse.getAccuracy();
-            lat += (Math.random() - 0.5) * distanceToDegreesLatitude(fudgeDistance);
-            lon += (Math.random() - 0.5) * distanceToDegreesLongitude(fudgeDistance, lat);
-        }
-
-        // wrap
-        lat = wrapLatitude(lat);
-        lon = wrapLongitude(lon);
-
-        // quantize (snap-to-grid)
-        double latGranularity = distanceToDegreesLatitude(COARSE_ACCURACY_M);
-        double lonGranularity = distanceToDegreesLongitude(COARSE_ACCURACY_M, lat);
-        long latQuantized = Math.round(lat / latGranularity);
-        long lonQuantized = Math.round(lon / lonGranularity);
-        lat = latQuantized * latGranularity;
-        lon = lonQuantized * lonGranularity;
-
-        // wrap again
-        lat = wrapLatitude(lat);
-        lon = wrapLongitude(lon);
-
-        // apply
-        coarse.setLatitude(lat);
-        coarse.setLongitude(lon);
-        coarse.setAccuracy((float)COARSE_ACCURACY_M);
-
-        return coarse;
-    }
-
-
-    private static Location getCoarseLocationExtra(Location location) {
-        Bundle extras = location.getExtras();
-        if (extras == null) return null;
-        Parcelable parcel = extras.getParcelable(EXTRA_COARSE_LOCATION);
-        if (parcel == null) return null;
-        if (!(parcel instanceof Location)) return null;
-        Location coarse = (Location) parcel;
-        if (coarse.getAccuracy() < COARSE_ACCURACY_M) return null;
-        return coarse;
-    }
-
-    private static Location addCoarseLocationExtra(Location location) {
-        Bundle extras = location.getExtras();
-        if (extras == null) extras = new Bundle();
-        Location coarse = createCoarse(location);
-        extras.putParcelable(EXTRA_COARSE_LOCATION, coarse);
-        location.setExtras(extras);
-        return coarse;
-    }
-
     private void log(String log) {
         if (Log.isLoggable(TAG, Log.VERBOSE)) {
             Slog.d(TAG, log);
@@ -1810,8 +1747,9 @@
                 for (String i : mDisabledProviders) {
                     pw.println("    " + i);
                 }
-
             }
+            pw.append("  ");
+            mBlacklist.dump(pw);
             if (mMockProviders.size() > 0) {
                 pw.println("  Mock Providers:");
                 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
@@ -1819,6 +1757,9 @@
                 }
             }
 
+            pw.append("  fudger: ");
+            mLocationFudger.dump(fd, pw,  args);
+
             if (args.length > 0 && "short".equals(args[0])) {
                 return;
             }
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 04267a3..bb5d552 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -48,7 +48,7 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.os.storage.IMountService;
 import android.os.storage.IMountServiceListener;
 import android.os.storage.IMountShutdownObserver;
@@ -1713,7 +1713,7 @@
             return false;
         }
 
-        final int packageUid = mPms.getPackageUid(packageName, UserId.getUserId(callerUid));
+        final int packageUid = mPms.getPackageUid(packageName, UserHandle.getUserId(callerUid));
 
         if (DEBUG_OBB) {
             Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 9ab1a9d..d6fed39 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -48,9 +48,10 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.os.Vibrator;
 import android.provider.Settings;
+import android.service.dreams.IDreamManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.AtomicFile;
@@ -148,6 +149,8 @@
     private AtomicFile mPolicyFile;
     private HashSet<String> mBlockedPackages = new HashSet<String>();
 
+    private IDreamManager mSandman;
+
     private static final int DB_VERSION = 1;
 
     private static final String TAG_BODY = "notification-policy";
@@ -634,6 +637,8 @@
     void systemReady() {
         mAudioService = IAudioService.Stub.asInterface(
                 ServiceManager.getService(Context.AUDIO_SERVICE));
+        mSandman = IDreamManager.Stub.asInterface(
+                ServiceManager.getService("dreams"));
 
         // no beeping until we're basically done booting
         mSystemReady = true;
@@ -972,6 +977,16 @@
                         | Notification.FLAG_NO_CLEAR;
             }
 
+            // Stop screensaver if the notification has a full-screen intent.
+            // (like an incoming phone call)
+            if (notification.fullScreenIntent != null && mSandman != null) {
+                try {
+                    mSandman.awaken();
+                } catch (RemoteException e) {
+                    // noop
+                }
+            }
+
             if (notification.icon != 0) {
                 StatusBarNotification n = new StatusBarNotification(pkg, id, tag,
                         r.uid, r.initialPid, score, notification);
@@ -1257,7 +1272,7 @@
 
     void checkCallerIsSystem() {
         int uid = Binder.getCallingUid();
-        if (uid == Process.SYSTEM_UID || uid == 0) {
+        if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) {
             return;
         }
         throw new SecurityException("Disallowed call for uid " + uid);
@@ -1265,13 +1280,13 @@
 
     void checkCallerIsSystemOrSameApp(String pkg) {
         int uid = Binder.getCallingUid();
-        if (uid == Process.SYSTEM_UID || uid == 0) {
+        if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) {
             return;
         }
         try {
             ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(
                     pkg, 0);
-            if (!UserId.isSameApp(ai.uid, uid)) {
+            if (!UserHandle.isSameApp(ai.uid, uid)) {
                 throw new SecurityException("Calling uid " + uid + " gave package"
                         + pkg + " which is owned by uid " + ai.uid);
             }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e8350c1..a6af144 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -50,6 +50,7 @@
 import com.android.internal.widget.LockSettingsService;
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.am.ActivityManagerService;
+import com.android.server.am.BatteryStatsService;
 import com.android.server.display.DisplayManagerService;
 import com.android.server.input.InputManagerService;
 import com.android.server.net.NetworkPolicyManagerService;
@@ -138,6 +139,7 @@
         DockObserver dock = null;
         UsbService usb = null;
         SerialService serial = null;
+        TwilightService twilight = null;
         UiModeManagerService uiMode = null;
         RecognitionManagerService recognition = null;
         ThrottleService throttle = null;
@@ -154,13 +156,12 @@
             power = new PowerManagerService();
             ServiceManager.addService(Context.POWER_SERVICE, power);
 
-            Slog.i(TAG, "Display Manager");
-            display = new DisplayManagerService();
-            ServiceManager.addService(Context.DISPLAY_SERVICE, display, true);
-
             Slog.i(TAG, "Activity Manager");
             context = ActivityManagerService.main(factoryTest);
-            display.setContext(context);
+
+            Slog.i(TAG, "Display Manager");
+            display = new DisplayManagerService(context);
+            ServiceManager.addService(Context.DISPLAY_SERVICE, display, true);
 
             Slog.i(TAG, "Telephony Registry");
             ServiceManager.addService("telephony.registry", new TelephonyRegistry(context));
@@ -230,7 +231,8 @@
 
             // only initialize the power service after we have started the
             // lights service, content providers and the battery service.
-            power.init(context, lights, ActivityManagerService.self(), battery, display);
+            power.init(context, lights, ActivityManagerService.self(), battery,
+                    BatteryStatsService.getService(), display);
 
             Slog.i(TAG, "Alarm Manager");
             alarm = new AlarmManagerService(context);
@@ -553,7 +555,7 @@
             try {
                 Slog.i(TAG, "Dock Observer");
                 // Listen for dock station changes
-                dock = new DockObserver(context, power);
+                dock = new DockObserver(context);
             } catch (Throwable e) {
                 reportWtf("starting DockObserver", e);
             }
@@ -585,9 +587,16 @@
             }
 
             try {
+                Slog.i(TAG, "Twilight Service");
+                twilight = new TwilightService(context);
+            } catch (Throwable e) {
+                reportWtf("starting TwilightService", e);
+            }
+
+            try {
                 Slog.i(TAG, "UI Mode Manager Service");
                 // Listen for UI mode changes
-                uiMode = new UiModeManagerService(context);
+                uiMode = new UiModeManagerService(context, twilight);
             } catch (Throwable e) {
                 reportWtf("starting UiModeManagerService", e);
             }
@@ -732,7 +741,12 @@
         w.getDefaultDisplay().getMetrics(metrics);
         context.getResources().updateConfiguration(config, metrics);
 
-        power.systemReady();
+        try {
+            power.systemReady(twilight);
+        } catch (Throwable e) {
+            reportWtf("making Power Manager Service ready", e);
+        }
+
         try {
             pm.systemReady();
         } catch (Throwable e) {
@@ -749,6 +763,7 @@
         final DockObserver dockF = dock;
         final UsbService usbF = usb;
         final ThrottleService throttleF = throttle;
+        final TwilightService twilightF = twilight;
         final UiModeManagerService uiModeF = uiMode;
         final AppWidgetService appWidgetF = appWidget;
         final WallpaperManagerService wallpaperF = wallpaper;
@@ -809,6 +824,11 @@
                     reportWtf("making USB Service ready", e);
                 }
                 try {
+                    if (twilightF != null) twilightF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("makin Twilight Service ready", e);
+                }
+                try {
                     if (uiModeF != null) uiModeF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making UI Mode Service ready", e);
diff --git a/services/java/com/android/server/TwilightService.java b/services/java/com/android/server/TwilightService.java
new file mode 100644
index 0000000..a7bce54
--- /dev/null
+++ b/services/java/com/android/server/TwilightService.java
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.text.format.DateUtils;
+import android.text.format.Time;
+import android.util.Slog;
+
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+
+import libcore.util.Objects;
+
+/**
+ * Figures out whether it's twilight time based on the user's location.
+ *
+ * Used by the UI mode manager and other components to adjust night mode
+ * effects based on sunrise and sunset.
+ */
+public final class TwilightService {
+    private static final String TAG = "TwilightService";
+
+    private static final boolean DEBUG = false;
+
+    private static final String ACTION_UPDATE_TWILIGHT_STATE =
+            "com.android.server.action.UPDATE_TWILIGHT_STATE";
+
+    private final Context mContext;
+    private final AlarmManager mAlarmManager;
+    private final LocationManager mLocationManager;
+    private final LocationHandler mLocationHandler;
+
+    private final Object mLock = new Object();
+
+    private final ArrayList<TwilightListenerRecord> mListeners =
+            new ArrayList<TwilightListenerRecord>();
+
+    private boolean mSystemReady;
+
+    private TwilightState mTwilightState;
+
+    public TwilightService(Context context) {
+        mContext = context;
+
+        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
+        mLocationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
+        mLocationHandler = new LocationHandler();
+    }
+
+    void systemReady() {
+        synchronized (mLock) {
+            mSystemReady = true;
+
+            IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+            filter.addAction(Intent.ACTION_TIME_CHANGED);
+            filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+            filter.addAction(ACTION_UPDATE_TWILIGHT_STATE);
+            mContext.registerReceiver(mUpdateLocationReceiver, filter);
+
+            if (!mListeners.isEmpty()) {
+                mLocationHandler.enableLocationUpdates();
+            }
+        }
+    }
+
+    /**
+     * Gets the current twilight state.
+     *
+     * @return The current twilight state, or null if no information is available.
+     */
+    public TwilightState getCurrentState() {
+        synchronized (mLock) {
+            return mTwilightState;
+        }
+    }
+
+    /**
+     * Listens for twilight time.
+     *
+     * @param listener The listener.
+     * @param handler The handler on which to post calls into the listener.
+     */
+    public void registerListener(TwilightListener listener, Handler handler) {
+        synchronized (mLock) {
+            mListeners.add(new TwilightListenerRecord(listener, handler));
+
+            if (mSystemReady && mListeners.size() == 1) {
+                mLocationHandler.enableLocationUpdates();
+            }
+        }
+    }
+
+    private void setTwilightState(TwilightState state) {
+        synchronized (mLock) {
+            if (!Objects.equal(mTwilightState, state)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Twilight state changed: " + state);
+                }
+
+                mTwilightState = state;
+                int count = mListeners.size();
+                for (int i = 0; i < count; i++) {
+                    mListeners.get(i).post();
+                }
+            }
+        }
+    }
+
+    // The user has moved if the accuracy circles of the two locations don't overlap.
+    private static boolean hasMoved(Location from, Location to) {
+        if (to == null) {
+            return false;
+        }
+
+        if (from == null) {
+            return true;
+        }
+
+        // if new location is older than the current one, the device hasn't moved.
+        if (to.getElapsedRealtimeNano() < from.getElapsedRealtimeNano()) {
+            return false;
+        }
+
+        // Get the distance between the two points.
+        float distance = from.distanceTo(to);
+
+        // Get the total accuracy radius for both locations.
+        float totalAccuracy = from.getAccuracy() + to.getAccuracy();
+
+        // If the distance is greater than the combined accuracy of the two
+        // points then they can't overlap and hence the user has moved.
+        return distance >= totalAccuracy;
+    }
+
+    /**
+     * Describes whether it is day or night.
+     * This object is immutable.
+     */
+    public static final class TwilightState {
+        private final boolean mIsNight;
+        private final long mYesterdaySunset;
+        private final long mTodaySunrise;
+        private final long mTodaySunset;
+        private final long mTomorrowSunrise;
+
+        TwilightState(boolean isNight,
+                long yesterdaySunset,
+                long todaySunrise, long todaySunset,
+                long tomorrowSunrise) {
+            mIsNight = isNight;
+            mYesterdaySunset = yesterdaySunset;
+            mTodaySunrise = todaySunrise;
+            mTodaySunset = todaySunset;
+            mTomorrowSunrise = tomorrowSunrise;
+        }
+
+        /**
+         * Returns true if it is currently night time.
+         */
+        public boolean isNight() {
+            return mIsNight;
+        }
+
+        /**
+         * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase,
+         * or -1 if the sun never sets.
+         */
+        public long getYesterdaySunset() {
+            return mYesterdaySunset;
+        }
+
+        /**
+         * Returns the time of today's sunrise in the System.currentTimeMillis() timebase,
+         * or -1 if the sun never rises.
+         */
+        public long getTodaySunrise() {
+            return mTodaySunrise;
+        }
+
+        /**
+         * Returns the time of today's sunset in the System.currentTimeMillis() timebase,
+         * or -1 if the sun never sets.
+         */
+        public long getTodaySunset() {
+            return mTodaySunset;
+        }
+
+        /**
+         * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase,
+         * or -1 if the sun never rises.
+         */
+        public long getTomorrowSunrise() {
+            return mTomorrowSunrise;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            return o instanceof TwilightState && equals((TwilightState)o);
+        }
+
+        public boolean equals(TwilightState other) {
+            return other != null
+                    && mIsNight == other.mIsNight
+                    && mYesterdaySunset == other.mYesterdaySunset
+                    && mTodaySunrise == other.mTodaySunrise
+                    && mTodaySunset == other.mTodaySunset
+                    && mTomorrowSunrise == other.mTomorrowSunrise;
+        }
+
+        @Override
+        public int hashCode() {
+            return 0; // don't care
+        }
+
+        @Override
+        public String toString() {
+            DateFormat f = DateFormat.getDateTimeInstance();
+            return "{TwilightState: isNight=" + mIsNight
+                    + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset))
+                    + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise))
+                    + ", mTodaySunset=" + f.format(new Date(mTodaySunset))
+                    + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise))
+                    + "}";
+        }
+    }
+
+    /**
+     * Listener for changes in twilight state.
+     */
+    public interface TwilightListener {
+        public void onTwilightStateChanged();
+    }
+
+    private static final class TwilightListenerRecord implements Runnable {
+        private final TwilightListener mListener;
+        private final Handler mHandler;
+
+        public TwilightListenerRecord(TwilightListener listener, Handler handler) {
+            mListener = listener;
+            mHandler = handler;
+        }
+
+        public void post() {
+            mHandler.post(this);
+        }
+
+        @Override
+        public void run() {
+            mListener.onTwilightStateChanged();
+        }
+    }
+
+    private final class LocationHandler extends Handler {
+        private static final int MSG_ENABLE_LOCATION_UPDATES = 1;
+        private static final int MSG_GET_NEW_LOCATION_UPDATE = 2;
+        private static final int MSG_PROCESS_NEW_LOCATION = 3;
+        private static final int MSG_DO_TWILIGHT_UPDATE = 4;
+
+        private static final long LOCATION_UPDATE_MS = 24 * DateUtils.HOUR_IN_MILLIS;
+        private static final long MIN_LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
+        private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20;
+        private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000;
+        private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX =
+                15 * DateUtils.MINUTE_IN_MILLIS;
+        private static final double FACTOR_GMT_OFFSET_LONGITUDE =
+                1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS;
+
+        private boolean mPassiveListenerEnabled;
+        private boolean mNetworkListenerEnabled;
+        private boolean mDidFirstInit;
+        private long mLastNetworkRegisterTime = -MIN_LOCATION_UPDATE_MS;
+        private long mLastUpdateInterval;
+        private Location mLocation;
+        private final TwilightCalculator mTwilightCalculator = new TwilightCalculator();
+
+        public void processNewLocation(Location location) {
+            Message msg = obtainMessage(MSG_PROCESS_NEW_LOCATION, location);
+            sendMessage(msg);
+        }
+
+        public void enableLocationUpdates() {
+            sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES);
+        }
+
+        public void requestLocationUpdate() {
+            sendEmptyMessage(MSG_GET_NEW_LOCATION_UPDATE);
+        }
+
+        public void requestTwilightUpdate() {
+            sendEmptyMessage(MSG_DO_TWILIGHT_UPDATE);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_PROCESS_NEW_LOCATION: {
+                    final Location location = (Location)msg.obj;
+                    final boolean hasMoved = hasMoved(mLocation, location);
+                    final boolean hasBetterAccuracy = mLocation == null
+                            || location.getAccuracy() < mLocation.getAccuracy();
+                    if (DEBUG) {
+                        Slog.d(TAG, "Processing new location: " + location
+                               + ", hasMoved=" + hasMoved
+                               + ", hasBetterAccuracy=" + hasBetterAccuracy);
+                    }
+                    if (hasMoved || hasBetterAccuracy) {
+                        setLocation(location);
+                    }
+                    break;
+                }
+
+                case MSG_GET_NEW_LOCATION_UPDATE:
+                    if (!mNetworkListenerEnabled) {
+                        // Don't do anything -- we are still trying to get a
+                        // location.
+                        return;
+                    }
+                    if ((mLastNetworkRegisterTime + MIN_LOCATION_UPDATE_MS) >=
+                            SystemClock.elapsedRealtime()) {
+                        // Don't do anything -- it hasn't been long enough
+                        // since we last requested an update.
+                        return;
+                    }
+
+                    // Unregister the current location monitor, so we can
+                    // register a new one for it to get an immediate update.
+                    mNetworkListenerEnabled = false;
+                    mLocationManager.removeUpdates(mEmptyLocationListener);
+
+                    // Fall through to re-register listener.
+                case MSG_ENABLE_LOCATION_UPDATES:
+                    // enable network provider to receive at least location updates for a given
+                    // distance.
+                    boolean networkLocationEnabled;
+                    try {
+                        networkLocationEnabled =
+                            mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
+                    } catch (Exception e) {
+                        // we may get IllegalArgumentException if network location provider
+                        // does not exist or is not yet installed.
+                        networkLocationEnabled = false;
+                    }
+                    if (!mNetworkListenerEnabled && networkLocationEnabled) {
+                        mNetworkListenerEnabled = true;
+                        mLastNetworkRegisterTime = SystemClock.elapsedRealtime();
+                        mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
+                                LOCATION_UPDATE_MS, 0, mEmptyLocationListener);
+
+                        if (!mDidFirstInit) {
+                            mDidFirstInit = true;
+                            if (mLocation == null) {
+                                retrieveLocation();
+                            }
+                        }
+                    }
+
+                    // enable passive provider to receive updates from location fixes (gps
+                    // and network).
+                    boolean passiveLocationEnabled;
+                    try {
+                        passiveLocationEnabled =
+                            mLocationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER);
+                    } catch (Exception e) {
+                        // we may get IllegalArgumentException if passive location provider
+                        // does not exist or is not yet installed.
+                        passiveLocationEnabled = false;
+                    }
+
+                    if (!mPassiveListenerEnabled && passiveLocationEnabled) {
+                        mPassiveListenerEnabled = true;
+                        mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
+                                0, LOCATION_UPDATE_DISTANCE_METER , mLocationListener);
+                    }
+
+                    if (!(mNetworkListenerEnabled && mPassiveListenerEnabled)) {
+                        mLastUpdateInterval *= 1.5;
+                        if (mLastUpdateInterval == 0) {
+                            mLastUpdateInterval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN;
+                        } else if (mLastUpdateInterval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) {
+                            mLastUpdateInterval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX;
+                        }
+                        sendEmptyMessageDelayed(MSG_ENABLE_LOCATION_UPDATES, mLastUpdateInterval);
+                    }
+                    break;
+
+                case MSG_DO_TWILIGHT_UPDATE:
+                    updateTwilightState();
+                    break;
+            }
+        }
+
+        private void retrieveLocation() {
+            Location location = null;
+            final Iterator<String> providers =
+                    mLocationManager.getProviders(new Criteria(), true).iterator();
+            while (providers.hasNext()) {
+                final Location lastKnownLocation =
+                        mLocationManager.getLastKnownLocation(providers.next());
+                // pick the most recent location
+                if (location == null || (lastKnownLocation != null &&
+                        location.getElapsedRealtimeNano() <
+                        lastKnownLocation.getElapsedRealtimeNano())) {
+                    location = lastKnownLocation;
+                }
+            }
+
+            // In the case there is no location available (e.g. GPS fix or network location
+            // is not available yet), the longitude of the location is estimated using the timezone,
+            // latitude and accuracy are set to get a good average.
+            if (location == null) {
+                Time currentTime = new Time();
+                currentTime.set(System.currentTimeMillis());
+                double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE *
+                        (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0));
+                location = new Location("fake");
+                location.setLongitude(lngOffset);
+                location.setLatitude(0);
+                location.setAccuracy(417000.0f);
+                location.setTime(System.currentTimeMillis());
+                location.setElapsedRealtimeNano(SystemClock.elapsedRealtimeNano());
+
+                if (DEBUG) {
+                    Slog.d(TAG, "Estimated location from timezone: " + location);
+                }
+            }
+
+            setLocation(location);
+        }
+
+        private void setLocation(Location location) {
+            mLocation = location;
+            updateTwilightState();
+        }
+
+        private void updateTwilightState() {
+            if (mLocation == null) {
+                setTwilightState(null);
+                return;
+            }
+
+            final long now = System.currentTimeMillis();
+
+            // calculate yesterday's twilight
+            mTwilightCalculator.calculateTwilight(now - DateUtils.DAY_IN_MILLIS,
+                    mLocation.getLatitude(), mLocation.getLongitude());
+            final long yesterdaySunset = mTwilightCalculator.mSunset;
+
+            // calculate today's twilight
+            mTwilightCalculator.calculateTwilight(now,
+                    mLocation.getLatitude(), mLocation.getLongitude());
+            final boolean isNight = (mTwilightCalculator.mState == TwilightCalculator.NIGHT);
+            final long todaySunrise = mTwilightCalculator.mSunrise;
+            final long todaySunset = mTwilightCalculator.mSunset;
+
+            // calculate tomorrow's twilight
+            mTwilightCalculator.calculateTwilight(now + DateUtils.DAY_IN_MILLIS,
+                    mLocation.getLatitude(), mLocation.getLongitude());
+            final long tomorrowSunrise = mTwilightCalculator.mSunrise;
+
+            // set twilight state
+            TwilightState state = new TwilightState(isNight, yesterdaySunset,
+                    todaySunrise, todaySunset, tomorrowSunrise);
+            if (DEBUG) {
+                Slog.d(TAG, "Updating twilight state: " + state);
+            }
+            setTwilightState(state);
+
+            // schedule next update
+            long nextUpdate = 0;
+            if (todaySunrise == -1 || todaySunset == -1) {
+                // In the case the day or night never ends the update is scheduled 12 hours later.
+                nextUpdate = now + 12 * DateUtils.HOUR_IN_MILLIS;
+            } else {
+                // add some extra time to be on the safe side.
+                nextUpdate += DateUtils.MINUTE_IN_MILLIS;
+
+                if (now > todaySunset) {
+                    nextUpdate += tomorrowSunrise;
+                } else if (now > todaySunrise) {
+                    nextUpdate += todaySunset;
+                } else {
+                    nextUpdate += todaySunrise;
+                }
+            }
+
+            if (DEBUG) {
+                Slog.d(TAG, "Next update in " + (nextUpdate - now) + " ms");
+            }
+
+            Intent updateIntent = new Intent(ACTION_UPDATE_TWILIGHT_STATE);
+            PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, updateIntent, 0);
+            mAlarmManager.cancel(pendingIntent);
+            mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent);
+        }
+    };
+
+    private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())
+                    && !intent.getBooleanExtra("state", false)) {
+                // Airplane mode is now off!
+                mLocationHandler.requestLocationUpdate();
+                return;
+            }
+
+            // Time zone has changed or alarm expired.
+            mLocationHandler.requestTwilightUpdate();
+        }
+    };
+
+    // A LocationListener to initialize the network location provider. The location updates
+    // are handled through the passive location provider.
+    private final LocationListener mEmptyLocationListener =  new LocationListener() {
+        public void onLocationChanged(Location location) {
+        }
+
+        public void onProviderDisabled(String provider) {
+        }
+
+        public void onProviderEnabled(String provider) {
+        }
+
+        public void onStatusChanged(String provider, int status, Bundle extras) {
+        }
+    };
+
+    private final LocationListener mLocationListener = new LocationListener() {
+        public void onLocationChanged(Location location) {
+            mLocationHandler.processNewLocation(location);
+        }
+
+        public void onProviderDisabled(String provider) {
+        }
+
+        public void onProviderEnabled(String provider) {
+        }
+
+        public void onStatusChanged(String provider, int status, Bundle extras) {
+        }
+    };
+}
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index 5299b71..617b29d 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -18,7 +18,6 @@
 
 import android.app.Activity;
 import android.app.ActivityManagerNative;
-import android.app.AlarmManager;
 import android.app.IUiModeManager;
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -32,55 +31,33 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
-import android.location.Criteria;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
 import android.os.BatteryManager;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.Handler;
-import android.os.Message;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemClock;
 import android.provider.Settings;
-import android.text.format.DateUtils;
-import android.text.format.Time;
 import android.util.Slog;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.Iterator;
 
 import com.android.internal.R;
 import com.android.internal.app.DisableCarModeActivity;
+import com.android.server.TwilightService.TwilightState;
 
 class UiModeManagerService extends IUiModeManager.Stub {
     private static final String TAG = UiModeManager.class.getSimpleName();
     private static final boolean LOG = false;
 
-    private static final String KEY_LAST_UPDATE_INTERVAL = "LAST_UPDATE_INTERVAL";
-
     // Enable launching of applications when entering the dock.
     private static final boolean ENABLE_LAUNCH_CAR_DOCK_APP = true;
     private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
 
-    private static final int MSG_UPDATE_TWILIGHT = 0;
-    private static final int MSG_ENABLE_LOCATION_UPDATES = 1;
-    private static final int MSG_GET_NEW_LOCATION_UPDATE = 2;
-
-    private static final long LOCATION_UPDATE_MS = 24 * DateUtils.HOUR_IN_MILLIS;
-    private static final long MIN_LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS;
-    private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20;
-    private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000;
-    private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = 15 * DateUtils.MINUTE_IN_MILLIS;
-    private static final double FACTOR_GMT_OFFSET_LONGITUDE = 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS;
-
-    private static final String ACTION_UPDATE_NIGHT_MODE = "com.android.server.action.UPDATE_NIGHT_MODE";
-
     private final Context mContext;
+    private final TwilightService mTwilightService;
+    private final Handler mHandler = new Handler();
 
     final Object mLock = new Object();
 
@@ -106,10 +83,6 @@
 
     private NotificationManager mNotificationManager;
 
-    private AlarmManager mAlarmManager;
-
-    private LocationManager mLocationManager;
-    private Location mLocation;
     private StatusBarManager mStatusBarManager;
     private final PowerManager.WakeLock mWakeLock;
 
@@ -206,15 +179,6 @@
         }
     };
 
-    private final BroadcastReceiver mTwilightUpdateReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (isDoingNightMode() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
-                mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT);
-            }
-        }
-    };
-
     private final BroadcastReceiver mDockModeReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -236,113 +200,24 @@
         }
     };
 
-    private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() {
+    private final TwilightService.TwilightListener mTwilightListener =
+            new TwilightService.TwilightListener() {
         @Override
-        public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())) {
-                if (!intent.getBooleanExtra("state", false)) {
-                    // Airplane mode is now off!
-                    mHandler.sendEmptyMessage(MSG_GET_NEW_LOCATION_UPDATE);
-                }
-            } else {
-                // Time zone has changed!
-                mHandler.sendEmptyMessage(MSG_GET_NEW_LOCATION_UPDATE);
-            }
+        public void onTwilightStateChanged() {
+            updateTwilight();
         }
     };
 
-    // A LocationListener to initialize the network location provider. The location updates
-    // are handled through the passive location provider.
-    private final LocationListener mEmptyLocationListener =  new LocationListener() {
-        public void onLocationChanged(Location location) {
-        }
-
-        public void onProviderDisabled(String provider) {
-        }
-
-        public void onProviderEnabled(String provider) {
-        }
-
-        public void onStatusChanged(String provider, int status, Bundle extras) {
-        }
-    };
-
-    private final LocationListener mLocationListener = new LocationListener() {
-
-        public void onLocationChanged(Location location) {
-            final boolean hasMoved = hasMoved(location);
-            final boolean hasBetterAccuracy = mLocation == null
-                    || location.getAccuracy() < mLocation.getAccuracy();
-            if (hasMoved || hasBetterAccuracy) {
-                synchronized (mLock) {
-                    mLocation = location;
-                    if (hasMoved && isDoingNightMode()
-                            && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
-                        mHandler.sendEmptyMessage(MSG_UPDATE_TWILIGHT);
-                    }
-                }
-            }
-        }
-
-        public void onProviderDisabled(String provider) {
-        }
-
-        public void onProviderEnabled(String provider) {
-        }
-
-        public void onStatusChanged(String provider, int status, Bundle extras) {
-        }
-
-        /*
-         * The user has moved if the accuracy circles of the two locations
-         * don't overlap.
-         */
-        private boolean hasMoved(Location location) {
-            if (location == null) {
-                return false;
-            }
-            if (mLocation == null) {
-                return true;
-            }
-
-            /* if new location is older than the current one, the devices hasn't
-             * moved.
-             */
-            if (location.getElapsedRealtimeNano() < mLocation.getElapsedRealtimeNano()) {
-                return false;
-            }
-
-            /* Get the distance between the two points */
-            float distance = mLocation.distanceTo(location);
-
-            /* Get the total accuracy radius for both locations */
-            float totalAccuracy = mLocation.getAccuracy() + location.getAccuracy();
-
-            /* If the distance is greater than the combined accuracy of the two
-             * points then they can't overlap and hence the user has moved.
-             */
-            return distance >= totalAccuracy;
-        }
-    };
-
-    public UiModeManagerService(Context context) {
+    public UiModeManagerService(Context context, TwilightService twilight) {
         mContext = context;
+        mTwilightService = twilight;
 
         ServiceManager.addService(Context.UI_MODE_SERVICE, this);
 
-        mAlarmManager =
-            (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
-        mLocationManager =
-            (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE);
-        mContext.registerReceiver(mTwilightUpdateReceiver,
-                new IntentFilter(ACTION_UPDATE_NIGHT_MODE));
         mContext.registerReceiver(mDockModeReceiver,
                 new IntentFilter(Intent.ACTION_DOCK_EVENT));
         mContext.registerReceiver(mBatteryReceiver,
                 new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
-        IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
-        mContext.registerReceiver(mUpdateLocationReceiver, filter);
 
         PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mWakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG);
@@ -360,6 +235,8 @@
 
         mNightMode = Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO);
+
+        mTwilightService.registerListener(mTwilightListener, mHandler);
     }
 
     public void disableCarMode(int flags) {
@@ -419,8 +296,8 @@
         synchronized (mLock) {
             mSystemReady = true;
             mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
+            updateComputedNightModeLocked();
             updateLocked(0, 0);
-            mHandler.sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES);
         }
     }
 
@@ -467,7 +344,7 @@
         }
         if (mCarModeEnabled) {
             if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
-                updateTwilightLocked();
+                updateComputedNightModeLocked();
                 uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
                         : Configuration.UI_MODE_NIGHT_NO;
             } else {
@@ -651,191 +528,20 @@
         }
     }
 
-    private final Handler mHandler = new Handler() {
-
-        boolean mPassiveListenerEnabled;
-        boolean mNetworkListenerEnabled;
-        boolean mDidFirstInit;
-        long mLastNetworkRegisterTime = -MIN_LOCATION_UPDATE_MS;
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_UPDATE_TWILIGHT:
-                    synchronized (mLock) {
-                        if (isDoingNightMode() && mLocation != null
-                                && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
-                            updateTwilightLocked();
-                            updateLocked(0, 0);
-                        }
-                    }
-                    break;
-                case MSG_GET_NEW_LOCATION_UPDATE:
-                    if (!mNetworkListenerEnabled) {
-                        // Don't do anything -- we are still trying to get a
-                        // location.
-                        return;
-                    }
-                    if ((mLastNetworkRegisterTime+MIN_LOCATION_UPDATE_MS)
-                            >= SystemClock.elapsedRealtime()) {
-                        // Don't do anything -- it hasn't been long enough
-                        // since we last requested an update.
-                        return;
-                    }
-
-                    // Unregister the current location monitor, so we can
-                    // register a new one for it to get an immediate update.
-                    mNetworkListenerEnabled = false;
-                    mLocationManager.removeUpdates(mEmptyLocationListener);
-
-                    // Fall through to re-register listener.
-                case MSG_ENABLE_LOCATION_UPDATES:
-                    // enable network provider to receive at least location updates for a given
-                    // distance.
-                    boolean networkLocationEnabled;
-                    try {
-                        networkLocationEnabled =
-                            mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
-                    } catch (Exception e) {
-                        // we may get IllegalArgumentException if network location provider
-                        // does not exist or is not yet installed.
-                        networkLocationEnabled = false;
-                    }
-                    if (!mNetworkListenerEnabled && networkLocationEnabled) {
-                        mNetworkListenerEnabled = true;
-                        mLastNetworkRegisterTime = SystemClock.elapsedRealtime();
-                        mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
-                                LOCATION_UPDATE_MS, 0, mEmptyLocationListener);
-
-                        if (!mDidFirstInit) {
-                            mDidFirstInit = true;
-                            if (mLocation == null) {
-                                retrieveLocation();
-                            }
-                            synchronized (mLock) {
-                                if (isDoingNightMode() && mLocation != null
-                                        && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
-                                    updateTwilightLocked();
-                                    updateLocked(0, 0);
-                                }
-                            }
-                        }
-                    }
-                   // enable passive provider to receive updates from location fixes (gps
-                   // and network).
-                   boolean passiveLocationEnabled;
-                    try {
-                        passiveLocationEnabled =
-                            mLocationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER);
-                    } catch (Exception e) {
-                        // we may get IllegalArgumentException if passive location provider
-                        // does not exist or is not yet installed.
-                        passiveLocationEnabled = false;
-                    }
-                    if (!mPassiveListenerEnabled && passiveLocationEnabled) {
-                        mPassiveListenerEnabled = true;
-                        mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
-                                0, LOCATION_UPDATE_DISTANCE_METER , mLocationListener);
-                    }
-                    if (!(mNetworkListenerEnabled && mPassiveListenerEnabled)) {
-                        long interval = msg.getData().getLong(KEY_LAST_UPDATE_INTERVAL);
-                        interval *= 1.5;
-                        if (interval == 0) {
-                            interval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN;
-                        } else if (interval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) {
-                            interval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX;
-                        }
-                        Bundle bundle = new Bundle();
-                        bundle.putLong(KEY_LAST_UPDATE_INTERVAL, interval);
-                        Message newMsg = mHandler.obtainMessage(MSG_ENABLE_LOCATION_UPDATES);
-                        newMsg.setData(bundle);
-                        mHandler.sendMessageDelayed(newMsg, interval);
-                    }
-                    break;
+    private void updateTwilight() {
+        synchronized (mLock) {
+            if (isDoingNightMode() && mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+                updateComputedNightModeLocked();
+                updateLocked(0, 0);
             }
         }
+    }
 
-        private void retrieveLocation() {
-            Location location = null;
-            final Iterator<String> providers =
-                    mLocationManager.getProviders(new Criteria(), true).iterator();
-            while (providers.hasNext()) {
-                final Location lastKnownLocation =
-                        mLocationManager.getLastKnownLocation(providers.next());
-                // pick the most recent location
-                if (location == null || (lastKnownLocation != null &&
-                        location.getElapsedRealtimeNano() <
-                        lastKnownLocation.getElapsedRealtimeNano())) {
-                    location = lastKnownLocation;
-                }
-            }
-            // In the case there is no location available (e.g. GPS fix or network location
-            // is not available yet), the longitude of the location is estimated using the timezone,
-            // latitude and accuracy are set to get a good average.
-            if (location == null) {
-                Time currentTime = new Time();
-                currentTime.set(System.currentTimeMillis());
-                double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE *
-                        (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0));
-                location = new Location("fake");
-                location.setLongitude(lngOffset);
-                location.setLatitude(0);
-                location.setAccuracy(417000.0f);
-                location.setTime(System.currentTimeMillis());
-                location.setElapsedRealtimeNano(SystemClock.elapsedRealtimeNano());
-            }
-            synchronized (mLock) {
-                mLocation = location;
-            }
+    private void updateComputedNightModeLocked() {
+        TwilightState state = mTwilightService.getCurrentState();
+        if (state != null) {
+            mComputedNightMode = state.isNight();
         }
-    };
-
-    void updateTwilightLocked() {
-        if (mLocation == null) {
-            return;
-        }
-        final long currentTime = System.currentTimeMillis();
-        boolean nightMode;
-        // calculate current twilight
-        TwilightCalculator tw = new TwilightCalculator();
-        tw.calculateTwilight(currentTime,
-                mLocation.getLatitude(), mLocation.getLongitude());
-        if (tw.mState == TwilightCalculator.DAY) {
-            nightMode = false;
-        } else {
-            nightMode = true;
-        }
-
-        // schedule next update
-        long nextUpdate = 0;
-        if (tw.mSunrise == -1 || tw.mSunset == -1) {
-            // In the case the day or night never ends the update is scheduled 12 hours later.
-            nextUpdate = currentTime + 12 * DateUtils.HOUR_IN_MILLIS;
-        } else {
-            final int mLastTwilightState = tw.mState;
-            // add some extra time to be on the save side.
-            nextUpdate += DateUtils.MINUTE_IN_MILLIS;
-            if (currentTime > tw.mSunset) {
-                // next update should be on the following day
-                tw.calculateTwilight(currentTime
-                        + DateUtils.DAY_IN_MILLIS, mLocation.getLatitude(),
-                        mLocation.getLongitude());
-            }
-
-            if (mLastTwilightState == TwilightCalculator.NIGHT) {
-                nextUpdate += tw.mSunrise;
-            } else {
-                nextUpdate += tw.mSunset;
-            }
-        }
-
-        Intent updateIntent = new Intent(ACTION_UPDATE_NIGHT_MODE);
-        PendingIntent pendingIntent =
-                PendingIntent.getBroadcast(mContext, 0, updateIntent, 0);
-        mAlarmManager.cancel(pendingIntent);
-        mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent);
-
-        mComputedNightMode = nightMode;
     }
 
     @Override
@@ -860,9 +566,8 @@
                     pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
             pw.print("  mHoldingConfiguration="); pw.print(mHoldingConfiguration);
                     pw.print(" mSystemReady="); pw.println(mSystemReady);
-            if (mLocation != null) {
-                pw.print("  mLocation="); pw.println(mLocation);
-            }
+            pw.print("  mTwilightService.getCurrentState()=");
+                    pw.println(mTwilightService.getCurrentState());
         }
     }
 }
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index d97d335..afd7d0e 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -45,9 +45,10 @@
 import android.os.FileObserver;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallbackList;
+import android.os.SELinux;
 import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.service.wallpaper.IWallpaperConnection;
 import android.service.wallpaper.IWallpaperEngine;
 import android.service.wallpaper.IWallpaperService;
@@ -422,9 +423,9 @@
             public void onReceive(Context context, Intent intent) {
                 String action = intent.getAction();
                 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                    switchUser(intent.getIntExtra(Intent.EXTRA_USERID, 0));
+                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
                 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
-                    removeUser(intent.getIntExtra(Intent.EXTRA_USERID, 0));
+                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
                 }
             }
         }, userFilter);
@@ -483,7 +484,7 @@
     public void clearWallpaper() {
         if (DEBUG) Slog.v(TAG, "clearWallpaper");
         synchronized (mLock) {
-            clearWallpaperLocked(false, UserId.getCallingUserId());
+            clearWallpaperLocked(false, UserHandle.getCallingUserId());
         }
     }
 
@@ -520,7 +521,7 @@
     public void setDimensionHints(int width, int height) throws RemoteException {
         checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
 
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
         WallpaperData wallpaper = mWallpaperMap.get(userId);
         if (wallpaper == null) {
             throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
@@ -551,14 +552,14 @@
 
     public int getWidthHint() throws RemoteException {
         synchronized (mLock) {
-            WallpaperData wallpaper = mWallpaperMap.get(UserId.getCallingUserId());
+            WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
             return wallpaper.width;
         }
     }
 
     public int getHeightHint() throws RemoteException {
         synchronized (mLock) {
-            WallpaperData wallpaper = mWallpaperMap.get(UserId.getCallingUserId());
+            WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
             return wallpaper.height;
         }
     }
@@ -573,7 +574,7 @@
             if (callingUid == android.os.Process.SYSTEM_UID) {
                 wallpaperUserId = mCurrentUserId;
             } else {
-                wallpaperUserId = UserId.getUserId(callingUid);
+                wallpaperUserId = UserHandle.getUserId(callingUid);
             }
             WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId);
             try {
@@ -596,7 +597,7 @@
     }
 
     public WallpaperInfo getWallpaperInfo() {
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
         synchronized (mLock) {
             WallpaperData wallpaper = mWallpaperMap.get(userId);
             if (wallpaper.connection != null) {
@@ -608,7 +609,7 @@
 
     public ParcelFileDescriptor setWallpaper(String name) {
         if (DEBUG) Slog.v(TAG, "setWallpaper");
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
         WallpaperData wallpaper = mWallpaperMap.get(userId);
         if (wallpaper == null) {
             throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
@@ -639,8 +640,12 @@
                         FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
                         -1, -1);
             }
-            ParcelFileDescriptor fd = ParcelFileDescriptor.open(new File(dir, WALLPAPER),
+            File file = new File(dir, WALLPAPER);
+            ParcelFileDescriptor fd = ParcelFileDescriptor.open(file,
                     MODE_CREATE|MODE_READ_WRITE);
+            if (!SELinux.restorecon(file)) {
+                return null;
+            }
             wallpaper.name = name;
             return fd;
         } catch (FileNotFoundException e) {
@@ -651,7 +656,7 @@
 
     public void setWallpaperComponent(ComponentName name) {
         if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
         WallpaperData wallpaper = mWallpaperMap.get(userId);
         if (wallpaper == null) {
             throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
@@ -763,10 +768,6 @@
             WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
             intent.setComponent(componentName);
             int serviceUserId = wallpaper.userId;
-            // Because the image wallpaper is running in the system ui
-            if (componentName.equals(wallpaper.imageWallpaperComponent)) {
-                serviceUserId = 0;
-            }
             intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
                     com.android.internal.R.string.wallpaper_binding_label);
             intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index c5b4a07..9edfad6 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -349,7 +349,7 @@
         }
 
         if (mMinScreenOff >= 0 && (mPower == null ||
-                mPower.timeSinceScreenOn() < mMinScreenOff)) {
+                mPower.timeSinceScreenWasLastOn() < mMinScreenOff)) {
             return "screen";
         }
 
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index e1c05b5..edbc624 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -303,6 +303,10 @@
                     mWifiStateMachine.sendMessage(Message.obtain(msg));
                     break;
                 }
+                case WifiManager.RSSI_PKTCNT_FETCH: {
+                    mWifiStateMachine.sendMessage(Message.obtain(msg));
+                    break;
+                }
                 default: {
                     Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg);
                     break;
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java
index 96ac493..56c0fdf 100644
--- a/services/java/com/android/server/WiredAccessoryObserver.java
+++ b/services/java/com/android/server/WiredAccessoryObserver.java
@@ -16,12 +16,12 @@
 
 package com.android.server;
 
-import android.app.ActivityManagerNative;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
@@ -39,7 +39,7 @@
 /**
  * <p>WiredAccessoryObserver monitors for a wired headset on the main board or dock.
  */
-class WiredAccessoryObserver extends UEventObserver {
+final class WiredAccessoryObserver extends UEventObserver {
     private static final String TAG = WiredAccessoryObserver.class.getSimpleName();
     private static final boolean LOG = true;
     private static final int BIT_HEADSET = (1 << 0);
@@ -50,40 +50,177 @@
     private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC|
                                                    BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL|
                                                    BIT_HDMI_AUDIO);
-    private static final int HEADSETS_WITH_MIC = BIT_HEADSET;
 
-    private static class UEventInfo {
-        private final String mDevName;
-        private final int mState1Bits;
-        private final int mState2Bits;
+    private final Object mLock = new Object();
 
-        public UEventInfo(String devName, int state1Bits, int state2Bits) {
-            mDevName = devName;
-            mState1Bits = state1Bits;
-            mState2Bits = state2Bits;
+    private final Context mContext;
+    private final WakeLock mWakeLock;  // held while there is a pending route change
+    private final AudioManager mAudioManager;
+    private final List<UEventInfo> mUEventInfo;
+
+    private int mHeadsetState;
+    private int mPrevHeadsetState;
+    private String mHeadsetName;
+
+    public WiredAccessoryObserver(Context context) {
+        mContext = context;
+
+        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryObserver");
+        mWakeLock.setReferenceCounted(false);
+        mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
+
+        mUEventInfo = makeObservedUEventList();
+
+        context.registerReceiver(new BootCompletedReceiver(),
+            new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
+    }
+
+    @Override
+    public void onUEvent(UEventObserver.UEvent event) {
+        if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());
+
+        try {
+            String devPath = event.get("DEVPATH");
+            String name = event.get("SWITCH_NAME");
+            int state = Integer.parseInt(event.get("SWITCH_STATE"));
+            synchronized (mLock) {
+                updateStateLocked(devPath, name, state);
+            }
+        } catch (NumberFormatException e) {
+            Slog.e(TAG, "Could not parse switch state from event " + event);
+        }
+    }
+
+    private void bootCompleted() {
+        synchronized (mLock) {
+            char[] buffer = new char[1024];
+            mPrevHeadsetState = mHeadsetState;
+
+            if (LOG) Slog.v(TAG, "init()");
+
+            for (int i = 0; i < mUEventInfo.size(); ++i) {
+                UEventInfo uei = mUEventInfo.get(i);
+                try {
+                    int curState;
+                    FileReader file = new FileReader(uei.getSwitchStatePath());
+                    int len = file.read(buffer, 0, 1024);
+                    file.close();
+                    curState = Integer.valueOf((new String(buffer, 0, len)).trim());
+
+                    if (curState > 0) {
+                        updateStateLocked(uei.getDevPath(), uei.getDevName(), curState);
+                    }
+                } catch (FileNotFoundException e) {
+                    Slog.w(TAG, uei.getSwitchStatePath() +
+                            " not found while attempting to determine initial switch state");
+                } catch (Exception e) {
+                    Slog.e(TAG, "" , e);
+                }
+            }
         }
 
-        public String getDevName() { return mDevName; }
+        // At any given time accessories could be inserted
+        // one on the board, one on the dock and one on HDMI:
+        // observe three UEVENTs
+        for (int i = 0; i < mUEventInfo.size(); ++i) {
+            UEventInfo uei = mUEventInfo.get(i);
+            startObserving("DEVPATH="+uei.getDevPath());
+        }
+    }
 
-        public String getDevPath() {
-            return String.format("/devices/virtual/switch/%s", mDevName);
+    private void updateStateLocked(String devPath, String name, int state) {
+        for (int i = 0; i < mUEventInfo.size(); ++i) {
+            UEventInfo uei = mUEventInfo.get(i);
+            if (devPath.equals(uei.getDevPath())) {
+                updateLocked(name, uei.computeNewHeadsetState(mHeadsetState, state));
+                return;
+            }
+        }
+    }
+
+    private void updateLocked(String newName, int newState) {
+        // Retain only relevant bits
+        int headsetState = newState & SUPPORTED_HEADSETS;
+        int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG;
+        int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL;
+        int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC);
+        boolean h2wStateChange = true;
+        boolean usbStateChange = true;
+        // reject all suspect transitions: only accept state changes from:
+        // - a: 0 heaset to 1 headset
+        // - b: 1 headset to 0 headset
+        if (LOG) Slog.v(TAG, "newState = "+newState+", headsetState = "+headsetState+","
+            + "mHeadsetState = "+mHeadsetState);
+        if (mHeadsetState == headsetState || ((h2w_headset & (h2w_headset - 1)) != 0)) {
+            Log.e(TAG, "unsetting h2w flag");
+            h2wStateChange = false;
+        }
+        // - c: 0 usb headset to 1 usb headset
+        // - d: 1 usb headset to 0 usb headset
+        if ((usb_headset_anlg >> 2) == 1 && (usb_headset_dgtl >> 3) == 1) {
+            Log.e(TAG, "unsetting usb flag");
+            usbStateChange = false;
+        }
+        if (!h2wStateChange && !usbStateChange) {
+            Log.e(TAG, "invalid transition, returning ...");
+            return;
         }
 
-        public String getSwitchStatePath() {
-            return String.format("/sys/class/switch/%s/state", mDevName);
+        mHeadsetName = newName;
+        mPrevHeadsetState = mHeadsetState;
+        mHeadsetState = headsetState;
+
+        mWakeLock.acquire();
+
+        Message msg = mHandler.obtainMessage(0, mHeadsetState, mPrevHeadsetState, mHeadsetName);
+        mHandler.sendMessage(msg);
+    }
+
+    private void setDevicesState(
+            int headsetState, int prevHeadsetState, String headsetName) {
+        synchronized (mLock) {
+            int allHeadsets = SUPPORTED_HEADSETS;
+            for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
+                if ((curHeadset & allHeadsets) != 0) {
+                    setDeviceStateLocked(curHeadset, headsetState, prevHeadsetState, headsetName);
+                    allHeadsets &= ~curHeadset;
+                }
+            }
         }
+    }
 
-        public boolean checkSwitchExists() {
-            File f = new File(getSwitchStatePath());
-            return ((null != f) && f.exists());
-        }
+    private void setDeviceStateLocked(int headset,
+            int headsetState, int prevHeadsetState, String headsetName) {
+        if ((headsetState & headset) != (prevHeadsetState & headset)) {
+            int device;
+            int state;
 
-        public int computeNewHeadsetState(int headsetState, int switchState) {
-            int preserveMask = ~(mState1Bits | mState2Bits);
-            int setBits = ((switchState == 1) ? mState1Bits :
-                          ((switchState == 2) ? mState2Bits : 0));
+            if ((headsetState & headset) != 0) {
+                state = 1;
+            } else {
+                state = 0;
+            }
 
-            return ((headsetState & preserveMask) | setBits);
+            if (headset == BIT_HEADSET) {
+                device = AudioManager.DEVICE_OUT_WIRED_HEADSET;
+            } else if (headset == BIT_HEADSET_NO_MIC){
+                device = AudioManager.DEVICE_OUT_WIRED_HEADPHONE;
+            } else if (headset == BIT_USB_HEADSET_ANLG) {
+                device = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET;
+            } else if (headset == BIT_USB_HEADSET_DGTL) {
+                device = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET;
+            } else if (headset == BIT_HDMI_AUDIO) {
+                device = AudioManager.DEVICE_OUT_AUX_DIGITAL;
+            } else {
+                Slog.e(TAG, "setDeviceState() invalid headset type: "+headset);
+                return;
+            }
+
+            if (LOG)
+                Slog.v(TAG, "device "+headsetName+((state == 1) ? " connected" : " disconnected"));
+
+            mAudioManager.setWiredDeviceConnectionState(device, state, headsetName);
         }
     }
 
@@ -130,189 +267,53 @@
         return retVal;
     }
 
-    private static List<UEventInfo> uEventInfo = makeObservedUEventList();
-
-    private int mHeadsetState;
-    private int mPrevHeadsetState;
-    private String mHeadsetName;
-
-    private final Context mContext;
-    private final WakeLock mWakeLock;  // held while there is a pending route change
-
-    private final AudioManager mAudioManager;
-
-    public WiredAccessoryObserver(Context context) {
-        mContext = context;
-        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryObserver");
-        mWakeLock.setReferenceCounted(false);
-        mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
-
-        context.registerReceiver(new BootCompletedReceiver(),
-            new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
-    }
-
-    private final class BootCompletedReceiver extends BroadcastReceiver {
-      @Override
-      public void onReceive(Context context, Intent intent) {
-        // At any given time accessories could be inserted
-        // one on the board, one on the dock and one on HDMI:
-        // observe three UEVENTs
-        init();  // set initial status
-        for (int i = 0; i < uEventInfo.size(); ++i) {
-            UEventInfo uei = uEventInfo.get(i);
-            startObserving("DEVPATH="+uei.getDevPath());
-        }
-      }
-    }
-
-    @Override
-    public void onUEvent(UEventObserver.UEvent event) {
-        if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());
-
-        try {
-            String devPath = event.get("DEVPATH");
-            String name = event.get("SWITCH_NAME");
-            int state = Integer.parseInt(event.get("SWITCH_STATE"));
-            updateState(devPath, name, state);
-        } catch (NumberFormatException e) {
-            Slog.e(TAG, "Could not parse switch state from event " + event);
-        }
-    }
-
-    private synchronized final void updateState(String devPath, String name, int state)
-    {
-        for (int i = 0; i < uEventInfo.size(); ++i) {
-            UEventInfo uei = uEventInfo.get(i);
-            if (devPath.equals(uei.getDevPath())) {
-                update(name, uei.computeNewHeadsetState(mHeadsetState, state));
-                return;
-            }
-        }
-    }
-
-    private synchronized final void init() {
-        char[] buffer = new char[1024];
-        mPrevHeadsetState = mHeadsetState;
-
-        if (LOG) Slog.v(TAG, "init()");
-
-        for (int i = 0; i < uEventInfo.size(); ++i) {
-            UEventInfo uei = uEventInfo.get(i);
-            try {
-                int curState;
-                FileReader file = new FileReader(uei.getSwitchStatePath());
-                int len = file.read(buffer, 0, 1024);
-                file.close();
-                curState = Integer.valueOf((new String(buffer, 0, len)).trim());
-
-                if (curState > 0) {
-                    updateState(uei.getDevPath(), uei.getDevName(), curState);
-                }
-
-            } catch (FileNotFoundException e) {
-                Slog.w(TAG, uei.getSwitchStatePath() +
-                        " not found while attempting to determine initial switch state");
-            } catch (Exception e) {
-                Slog.e(TAG, "" , e);
-            }
-        }
-    }
-
-    private synchronized final void update(String newName, int newState) {
-        // Retain only relevant bits
-        int headsetState = newState & SUPPORTED_HEADSETS;
-        int newOrOld = headsetState | mHeadsetState;
-        int delay = 0;
-        int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG;
-        int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL;
-        int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC);
-        boolean h2wStateChange = true;
-        boolean usbStateChange = true;
-        // reject all suspect transitions: only accept state changes from:
-        // - a: 0 heaset to 1 headset
-        // - b: 1 headset to 0 headset
-        if (LOG) Slog.v(TAG, "newState = "+newState+", headsetState = "+headsetState+","
-            + "mHeadsetState = "+mHeadsetState);
-        if (mHeadsetState == headsetState || ((h2w_headset & (h2w_headset - 1)) != 0)) {
-            Log.e(TAG, "unsetting h2w flag");
-            h2wStateChange = false;
-        }
-        // - c: 0 usb headset to 1 usb headset
-        // - d: 1 usb headset to 0 usb headset
-        if ((usb_headset_anlg >> 2) == 1 && (usb_headset_dgtl >> 3) == 1) {
-            Log.e(TAG, "unsetting usb flag");
-            usbStateChange = false;
-        }
-        if (!h2wStateChange && !usbStateChange) {
-            Log.e(TAG, "invalid transition, returning ...");
-            return;
-        }
-
-        mHeadsetName = newName;
-        mPrevHeadsetState = mHeadsetState;
-        mHeadsetState = headsetState;
-
-        mWakeLock.acquire();
-        mHandler.sendMessage(mHandler.obtainMessage(0,
-                                                    mHeadsetState,
-                                                    mPrevHeadsetState,
-                                                    mHeadsetName));
-    }
-
-    private synchronized final void setDevicesState(int headsetState,
-                                                    int prevHeadsetState,
-                                                    String headsetName) {
-        int allHeadsets = SUPPORTED_HEADSETS;
-        for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
-            if ((curHeadset & allHeadsets) != 0) {
-                setDeviceState(curHeadset, headsetState, prevHeadsetState, headsetName);
-                allHeadsets &= ~curHeadset;
-            }
-        }
-    }
-
-    private final void setDeviceState(int headset,
-                                      int headsetState,
-                                      int prevHeadsetState,
-                                      String headsetName) {
-        if ((headsetState & headset) != (prevHeadsetState & headset)) {
-            int device;
-            int state;
-
-            if ((headsetState & headset) != 0) {
-                state = 1;
-            } else {
-                state = 0;
-            }
-
-            if (headset == BIT_HEADSET) {
-                device = AudioManager.DEVICE_OUT_WIRED_HEADSET;
-            } else if (headset == BIT_HEADSET_NO_MIC){
-                device = AudioManager.DEVICE_OUT_WIRED_HEADPHONE;
-            } else if (headset == BIT_USB_HEADSET_ANLG) {
-                device = AudioManager.DEVICE_OUT_ANLG_DOCK_HEADSET;
-            } else if (headset == BIT_USB_HEADSET_DGTL) {
-                device = AudioManager.DEVICE_OUT_DGTL_DOCK_HEADSET;
-            } else if (headset == BIT_HDMI_AUDIO) {
-                device = AudioManager.DEVICE_OUT_AUX_DIGITAL;
-            } else {
-                Slog.e(TAG, "setDeviceState() invalid headset type: "+headset);
-                return;
-            }
-
-            if (LOG)
-                Slog.v(TAG, "device "+headsetName+((state == 1) ? " connected" : " disconnected"));
-
-            mAudioManager.setWiredDeviceConnectionState(device, state, headsetName);
-        }
-    }
-
-    private final Handler mHandler = new Handler() {
+    private final Handler mHandler = new Handler(Looper.myLooper(), null, true) {
         @Override
         public void handleMessage(Message msg) {
             setDevicesState(msg.arg1, msg.arg2, (String)msg.obj);
             mWakeLock.release();
         }
     };
+
+    private static final class UEventInfo {
+        private final String mDevName;
+        private final int mState1Bits;
+        private final int mState2Bits;
+
+        public UEventInfo(String devName, int state1Bits, int state2Bits) {
+            mDevName = devName;
+            mState1Bits = state1Bits;
+            mState2Bits = state2Bits;
+        }
+
+        public String getDevName() { return mDevName; }
+
+        public String getDevPath() {
+            return String.format("/devices/virtual/switch/%s", mDevName);
+        }
+
+        public String getSwitchStatePath() {
+            return String.format("/sys/class/switch/%s/state", mDevName);
+        }
+
+        public boolean checkSwitchExists() {
+            File f = new File(getSwitchStatePath());
+            return ((null != f) && f.exists());
+        }
+
+        public int computeNewHeadsetState(int headsetState, int switchState) {
+            int preserveMask = ~(mState1Bits | mState2Bits);
+            int setBits = ((switchState == 1) ? mState1Bits :
+                          ((switchState == 2) ? mState2Bits : 0));
+
+            return ((headsetState & preserveMask) | setBits);
+        }
+    }
+
+    private final class BootCompletedReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            bootCompleted();
+        }
+    }
 }
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 533c2cd..e222936 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -51,7 +51,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
@@ -226,7 +226,7 @@
 
         ServiceLookupResult res =
             retrieveServiceLocked(service, resolvedType,
-                    callingPid, callingUid, UserId.getUserId(callingUid));
+                    callingPid, callingUid, UserHandle.getUserId(callingUid), true);
         if (res == null) {
             return null;
         }
@@ -277,8 +277,10 @@
         }
 
         // If this service is active, make sure it is stopped.
-        ServiceLookupResult r = findServiceLocked(service, resolvedType,
-                callerApp == null ? UserId.getCallingUserId() : callerApp.userId);
+        ServiceLookupResult r = retrieveServiceLocked(service, resolvedType,
+                Binder.getCallingPid(), Binder.getCallingUid(),
+                callerApp == null ? UserHandle.getCallingUserId() : callerApp.userId,
+                false);
         if (r != null) {
             if (r.record != null) {
                 final long origId = Binder.clearCallingIdentity();
@@ -296,8 +298,9 @@
     }
 
     IBinder peekServiceLocked(Intent service, String resolvedType) {
-        ServiceLookupResult r = findServiceLocked(service, resolvedType,
-                UserId.getCallingUserId());
+        ServiceLookupResult r = retrieveServiceLocked(service, resolvedType,
+                Binder.getCallingPid(), Binder.getCallingUid(),
+                UserHandle.getCallingUserId(), false);
 
         IBinder ret = null;
         if (r != null) {
@@ -471,7 +474,7 @@
 
         ServiceLookupResult res =
             retrieveServiceLocked(service, resolvedType,
-                    Binder.getCallingPid(), Binder.getCallingUid(), userId);
+                    Binder.getCallingPid(), Binder.getCallingUid(), userId, true);
         if (res == null) {
             return 0;
         }
@@ -482,7 +485,7 @@
                 res.record.serviceInfo.name, res.record.serviceInfo.flags)) {
             userId = 0;
             res = retrieveServiceLocked(service, resolvedType, Binder.getCallingPid(),
-                    Binder.getCallingUid(), 0);
+                    Binder.getCallingUid(), 0, true);
         }
         ServiceRecord s = res.record;
 
@@ -689,60 +692,6 @@
             record = _record;
             permission = _permission;
         }
-    };
-
-    private ServiceLookupResult findServiceLocked(Intent service,
-            String resolvedType, int userId) {
-        ServiceRecord r = null;
-        if (service.getComponent() != null) {
-            r = mServiceMap.getServiceByName(service.getComponent(), userId);
-        }
-        if (r == null) {
-            Intent.FilterComparison filter = new Intent.FilterComparison(service);
-            r = mServiceMap.getServiceByIntent(filter, userId);
-        }
-
-        if (r == null) {
-            try {
-                ResolveInfo rInfo =
-                    AppGlobals.getPackageManager().resolveService(
-                                service, resolvedType, 0, userId);
-                ServiceInfo sInfo =
-                    rInfo != null ? rInfo.serviceInfo : null;
-                if (sInfo == null) {
-                    return null;
-                }
-
-                ComponentName name = new ComponentName(
-                        sInfo.applicationInfo.packageName, sInfo.name);
-                r = mServiceMap.getServiceByName(name, Binder.getOrigCallingUser());
-            } catch (RemoteException ex) {
-                // pm is in same process, this will never happen.
-            }
-        }
-        if (r != null) {
-            int callingPid = Binder.getCallingPid();
-            int callingUid = Binder.getCallingUid();
-            if (mAm.checkComponentPermission(r.permission,
-                    callingPid, callingUid, r.appInfo.uid, r.exported)
-                    != PackageManager.PERMISSION_GRANTED) {
-                if (!r.exported) {
-                    Slog.w(TAG, "Permission Denial: Accessing service " + r.name
-                            + " from pid=" + callingPid
-                            + ", uid=" + callingUid
-                            + " that is not exported from uid " + r.appInfo.uid);
-                    return new ServiceLookupResult(null, "not exported from uid "
-                            + r.appInfo.uid);
-                }
-                Slog.w(TAG, "Permission Denial: Accessing service " + r.name
-                        + " from pid=" + callingPid
-                        + ", uid=" + callingUid
-                        + " requires " + r.permission);
-                return new ServiceLookupResult(null, r.permission);
-            }
-            return new ServiceLookupResult(r, null);
-        }
-        return null;
     }
 
     private class ServiceRestarter implements Runnable {
@@ -760,7 +709,8 @@
     }
 
     private ServiceLookupResult retrieveServiceLocked(Intent service,
-            String resolvedType, int callingPid, int callingUid, int userId) {
+            String resolvedType, int callingPid, int callingUid, int userId,
+            boolean createIfNeeded) {
         ServiceRecord r = null;
         if (DEBUG_SERVICE) Slog.v(TAG, "retrieveServiceLocked: " + service
                 + " type=" + resolvedType + " callingUid=" + callingUid);
@@ -796,7 +746,7 @@
                     sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
                 }
                 r = mServiceMap.getServiceByName(name, userId);
-                if (r == null) {
+                if (r == null && createIfNeeded) {
                     Intent.FilterComparison filter = new Intent.FilterComparison(
                             service.cloneFilter());
                     ServiceRestarter res = new ServiceRestarter();
@@ -809,8 +759,8 @@
                     }
                     r = new ServiceRecord(mAm, ss, name, filter, sInfo, res);
                     res.setService(r);
-                    mServiceMap.putServiceByName(name, UserId.getUserId(r.appInfo.uid), r);
-                    mServiceMap.putServiceByIntent(filter, UserId.getUserId(r.appInfo.uid), r);
+                    mServiceMap.putServiceByName(name, UserHandle.getUserId(r.appInfo.uid), r);
+                    mServiceMap.putServiceByIntent(filter, UserHandle.getUserId(r.appInfo.uid), r);
 
                     // Make sure this component isn't in the pending list.
                     int N = mPendingServices.size();
@@ -897,87 +847,94 @@
         boolean canceled = false;
 
         final long now = SystemClock.uptimeMillis();
-        long minDuration = SERVICE_RESTART_DURATION;
-        long resetTime = SERVICE_RESET_RUN_DURATION;
 
         if ((r.serviceInfo.applicationInfo.flags
-                &ApplicationInfo.FLAG_PERSISTENT) != 0) {
-            minDuration /= 4;
-        }
+                &ApplicationInfo.FLAG_PERSISTENT) == 0) {
+            long minDuration = SERVICE_RESTART_DURATION;
+            long resetTime = SERVICE_RESET_RUN_DURATION;
 
-        // Any delivered but not yet finished starts should be put back
-        // on the pending list.
-        final int N = r.deliveredStarts.size();
-        if (N > 0) {
-            for (int i=N-1; i>=0; i--) {
-                ServiceRecord.StartItem si = r.deliveredStarts.get(i);
-                si.removeUriPermissionsLocked();
-                if (si.intent == null) {
-                    // We'll generate this again if needed.
-                } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
-                        && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
-                    r.pendingStarts.add(0, si);
-                    long dur = SystemClock.uptimeMillis() - si.deliveredTime;
-                    dur *= 2;
-                    if (minDuration < dur) minDuration = dur;
-                    if (resetTime < dur) resetTime = dur;
-                } else {
-                    Slog.w(TAG, "Canceling start item " + si.intent + " in service "
-                            + r.name);
-                    canceled = true;
+            // Any delivered but not yet finished starts should be put back
+            // on the pending list.
+            final int N = r.deliveredStarts.size();
+            if (N > 0) {
+                for (int i=N-1; i>=0; i--) {
+                    ServiceRecord.StartItem si = r.deliveredStarts.get(i);
+                    si.removeUriPermissionsLocked();
+                    if (si.intent == null) {
+                        // We'll generate this again if needed.
+                    } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
+                            && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
+                        r.pendingStarts.add(0, si);
+                        long dur = SystemClock.uptimeMillis() - si.deliveredTime;
+                        dur *= 2;
+                        if (minDuration < dur) minDuration = dur;
+                        if (resetTime < dur) resetTime = dur;
+                    } else {
+                        Slog.w(TAG, "Canceling start item " + si.intent + " in service "
+                                + r.name);
+                        canceled = true;
+                    }
                 }
+                r.deliveredStarts.clear();
             }
-            r.deliveredStarts.clear();
-        }
 
-        r.totalRestartCount++;
-        if (r.restartDelay == 0) {
-            r.restartCount++;
-            r.restartDelay = minDuration;
-        } else {
-            // If it has been a "reasonably long time" since the service
-            // was started, then reset our restart duration back to
-            // the beginning, so we don't infinitely increase the duration
-            // on a service that just occasionally gets killed (which is
-            // a normal case, due to process being killed to reclaim memory).
-            if (now > (r.restartTime+resetTime)) {
-                r.restartCount = 1;
+            r.totalRestartCount++;
+            if (r.restartDelay == 0) {
+                r.restartCount++;
                 r.restartDelay = minDuration;
             } else {
-                if ((r.serviceInfo.applicationInfo.flags
-                        &ApplicationInfo.FLAG_PERSISTENT) != 0) {
-                    // Services in peristent processes will restart much more
-                    // quickly, since they are pretty important.  (Think SystemUI).
-                    r.restartDelay += minDuration/2;
+                // If it has been a "reasonably long time" since the service
+                // was started, then reset our restart duration back to
+                // the beginning, so we don't infinitely increase the duration
+                // on a service that just occasionally gets killed (which is
+                // a normal case, due to process being killed to reclaim memory).
+                if (now > (r.restartTime+resetTime)) {
+                    r.restartCount = 1;
+                    r.restartDelay = minDuration;
                 } else {
-                    r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
-                    if (r.restartDelay < minDuration) {
-                        r.restartDelay = minDuration;
+                    if ((r.serviceInfo.applicationInfo.flags
+                            &ApplicationInfo.FLAG_PERSISTENT) != 0) {
+                        // Services in peristent processes will restart much more
+                        // quickly, since they are pretty important.  (Think SystemUI).
+                        r.restartDelay += minDuration/2;
+                    } else {
+                        r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
+                        if (r.restartDelay < minDuration) {
+                            r.restartDelay = minDuration;
+                        }
                     }
                 }
             }
-        }
 
-        r.nextRestartTime = now + r.restartDelay;
+            r.nextRestartTime = now + r.restartDelay;
 
-        // Make sure that we don't end up restarting a bunch of services
-        // all at the same time.
-        boolean repeat;
-        do {
-            repeat = false;
-            for (int i=mRestartingServices.size()-1; i>=0; i--) {
-                ServiceRecord r2 = mRestartingServices.get(i);
-                if (r2 != r && r.nextRestartTime
-                        >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
-                        && r.nextRestartTime
-                        < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
-                    r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
-                    r.restartDelay = r.nextRestartTime - now;
-                    repeat = true;
-                    break;
+            // Make sure that we don't end up restarting a bunch of services
+            // all at the same time.
+            boolean repeat;
+            do {
+                repeat = false;
+                for (int i=mRestartingServices.size()-1; i>=0; i--) {
+                    ServiceRecord r2 = mRestartingServices.get(i);
+                    if (r2 != r && r.nextRestartTime
+                            >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
+                            && r.nextRestartTime
+                            < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
+                        r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
+                        r.restartDelay = r.nextRestartTime - now;
+                        repeat = true;
+                        break;
+                    }
                 }
-            }
-        } while (repeat);
+            } while (repeat);
+
+        } else {
+            // Persistent processes are immediately restrted, so there is no
+            // reason to hold of on restarting their services.
+            r.totalRestartCount++;
+            r.restartCount = 0;
+            r.restartDelay = 0;
+            r.nextRestartTime = now;
+        }
 
         if (!mRestartingServices.contains(r)) {
             mRestartingServices.add(r);
@@ -1494,6 +1451,7 @@
 
     boolean attachApplicationLocked(ProcessRecord proc, String processName) throws Exception {
         boolean didSomething = false;
+        // Collect any services that are waiting for this process to come up.
         if (mPendingServices.size() > 0) {
             ServiceRecord sr = null;
             try {
@@ -1515,6 +1473,22 @@
                 throw e;
             }
         }
+        // Also, if there are any services that are waiting to restart and
+        // would run in this process, now is a good time to start them.  It would
+        // be weird to bring up the process but arbitrarily not let the services
+        // run at this point just because their restart time hasn't come up.
+        if (mRestartingServices.size() > 0) {
+            ServiceRecord sr = null;
+            for (int i=0; i<mRestartingServices.size(); i++) {
+                sr = mRestartingServices.get(i);
+                if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
+                        || !processName.equals(sr.processName))) {
+                    continue;
+                }
+                mAm.mHandler.removeCallbacks(sr.restarter);
+                mAm.mHandler.post(sr.restarter);
+            }
+        }
         return didSomething;
     }
 
@@ -1751,28 +1725,60 @@
         ArrayList<ActivityManager.RunningServiceInfo> res
                 = new ArrayList<ActivityManager.RunningServiceInfo>();
 
-        int userId = UserId.getUserId(Binder.getCallingUid());
-        if (mServiceMap.getAllServices(userId).size() > 0) {
-            Iterator<ServiceRecord> it
-                    = mServiceMap.getAllServices(userId).iterator();
-            while (it.hasNext() && res.size() < maxNum) {
-                res.add(makeRunningServiceInfoLocked(it.next()));
-            }
-        }
+        final int uid = Binder.getCallingUid();
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            if (ActivityManager.checkUidPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    uid) == PackageManager.PERMISSION_GRANTED) {
+                List<UserInfo> users = mAm.getUserManager().getUsers();
+                for (int ui=0; ui<users.size() && res.size() < maxNum; ui++) {
+                    final UserInfo user = users.get(ui);
+                    if (mServiceMap.getAllServices(user.id).size() > 0) {
+                        Iterator<ServiceRecord> it = mServiceMap.getAllServices(
+                                user.id).iterator();
+                        while (it.hasNext() && res.size() < maxNum) {
+                            res.add(makeRunningServiceInfoLocked(it.next()));
+                        }
+                    }
+                }
 
-        for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
-            ServiceRecord r = mRestartingServices.get(i);
-            ActivityManager.RunningServiceInfo info =
-                    makeRunningServiceInfoLocked(r);
-            info.restarting = r.nextRestartTime;
-            res.add(info);
+                for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
+                    ServiceRecord r = mRestartingServices.get(i);
+                    ActivityManager.RunningServiceInfo info =
+                            makeRunningServiceInfoLocked(r);
+                    info.restarting = r.nextRestartTime;
+                    res.add(info);
+                }
+            } else {
+                int userId = UserHandle.getUserId(uid);
+                if (mServiceMap.getAllServices(userId).size() > 0) {
+                    Iterator<ServiceRecord> it
+                            = mServiceMap.getAllServices(userId).iterator();
+                    while (it.hasNext() && res.size() < maxNum) {
+                        res.add(makeRunningServiceInfoLocked(it.next()));
+                    }
+                }
+
+                for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
+                    ServiceRecord r = mRestartingServices.get(i);
+                    if (r.userId == userId) {
+                        ActivityManager.RunningServiceInfo info =
+                                makeRunningServiceInfoLocked(r);
+                        info.restarting = r.nextRestartTime;
+                        res.add(info);
+                    }
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
 
         return res;
     }
 
     public PendingIntent getRunningServiceControlPanelLocked(ComponentName name) {
-        int userId = UserId.getUserId(Binder.getCallingUid());
+        int userId = UserHandle.getUserId(Binder.getCallingUid());
         ServiceRecord r = mServiceMap.getServiceByName(name, userId);
         if (r != null) {
             for (ArrayList<ConnectionRecord> conn : r.connections.values()) {
@@ -1836,7 +1842,8 @@
         pw.println("ACTIVITY MANAGER SERVICES (dumpsys activity services)");
         try {
             List<UserInfo> users = mAm.getUserManager().getUsers();
-            for (UserInfo user : users) {
+            for (int ui=0; ui<users.size(); ui++) {
+                final UserInfo user = users.get(ui);
                 if (mServiceMap.getAllServices(user.id).size() > 0) {
                     boolean printed = false;
                     long nowReal = SystemClock.elapsedRealtime();
@@ -1852,7 +1859,10 @@
                             continue;
                         }
                         if (!printed) {
-                            pw.println("  Active services:");
+                            if (ui > 0) {
+                                pw.println();
+                            }
+                            pw.println("  User " + user.id + " active services:");
                             printed = true;
                         }
                         if (needSep) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index d3ec9f7..cb15b3b 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -27,7 +27,6 @@
 import com.android.server.SystemServer;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityStack.ActivityState;
-import com.android.server.pm.UserManagerService;
 import com.android.server.wm.WindowManagerService;
 
 import dalvik.system.Zygote;
@@ -52,7 +51,6 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
-import android.app.Service;
 import android.app.backup.IBackupManager;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -107,11 +105,12 @@
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.SELinux;
 import android.os.ServiceManager;
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.text.format.Time;
@@ -145,7 +144,6 @@
 import java.io.StringWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -686,6 +684,18 @@
     int mLruSeq = 0;
 
     /**
+     * Keep track of the non-hidden/empty process we last found, to help
+     * determine how to distribute hidden/empty processes next time.
+     */
+    int mNumNonHiddenProcs = 0;
+
+    /**
+     * Keep track of the number of hidden procs, to balance oom adj
+     * distribution between those and empty procs.
+     */
+    int mNumHiddenProcs = 0;
+
+    /**
      * Keep track of the number of service processes we last found, to
      * determine on the next iteration which should be B services.
      */
@@ -1072,7 +1082,7 @@
                     boolean restart = (msg.arg2 == 1);
                     String pkg = (String) msg.obj;
                     forceStopPackageLocked(pkg, uid, restart, false, true, false,
-                            UserId.getUserId(uid));
+                            UserHandle.getUserId(uid));
                 }
             } break;
             case FINALIZE_PENDING_INTENT_MSG: {
@@ -1817,7 +1827,7 @@
             if (procs == null) return null;
             final int N = procs.size();
             for (int i = 0; i < N; i++) {
-                if (UserId.isSameUser(procs.keyAt(i), uid)) return procs.valueAt(i);
+                if (UserHandle.isSameUser(procs.keyAt(i), uid)) return procs.valueAt(i);
             }
         }
         ProcessRecord proc = mProcessNames.get(processName, uid);
@@ -1952,7 +1962,7 @@
                 mPidsSelfLocked.remove(app.pid);
                 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
             }
-            app.pid = 0;
+            app.setPid(0);
         }
 
         if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
@@ -1968,10 +1978,20 @@
             int uid = app.uid;
 
             int[] gids = null;
+            int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
             if (!app.isolated) {
                 try {
-                    gids = mContext.getPackageManager().getPackageGids(
-                            app.info.packageName);
+                    final PackageManager pm = mContext.getPackageManager();
+                    gids = pm.getPackageGids(app.info.packageName);
+                    if (pm.checkPermission(
+                            android.Manifest.permission.READ_EXTERNAL_STORAGE, app.info.packageName)
+                            == PERMISSION_GRANTED) {
+                        if (Environment.isExternalStorageEmulated()) {
+                            mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
+                        } else {
+                            mountExternal = Zygote.MOUNT_EXTERNAL_SINGLEUSER;
+                        }
+                    }
                 } catch (PackageManager.NameNotFoundException e) {
                     Slog.w(TAG, "Unable to retrieve gids", e);
                 }
@@ -2013,7 +2033,7 @@
             // Start the process.  It will either succeed and return a result containing
             // the PID of the new process, or else throw a RuntimeException.
             Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
-                    app.processName, uid, uid, gids, debugFlags,
+                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                     app.info.targetSdkVersion, null, null);
 
             BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
@@ -2055,7 +2075,7 @@
             }
             buf.append("}");
             Slog.i(TAG, buf.toString());
-            app.pid = startResult.pid;
+            app.setPid(startResult.pid);
             app.usingWrapper = startResult.usingWrapper;
             app.removed = false;
             synchronized (mPidsSelfLocked) {
@@ -2067,7 +2087,7 @@
             }
         } catch (RuntimeException e) {
             // XXX do better error recovery.
-            app.pid = 0;
+            app.setPid(0);
             Slog.e(TAG, "Failure starting process " + app.processName, e);
         }
     }
@@ -2183,7 +2203,7 @@
     }
 
     void enforceNotIsolatedCaller(String caller) {
-        if (UserId.isIsolated(Binder.getCallingUid())) {
+        if (UserHandle.isIsolated(Binder.getCallingUid())) {
             throw new SecurityException("Isolated process not allowed to call " + caller);
         }
     }
@@ -2312,7 +2332,7 @@
             String resultWho, int requestCode, int startFlags,
             String profileFile, ParcelFileDescriptor profileFd, Bundle options) {
         return startActivityAsUser(caller, intent, resolvedType, resultTo, resultWho, requestCode,
-                startFlags, profileFile, profileFd, options, UserId.getCallingUserId());
+                startFlags, profileFile, profileFd, options, UserHandle.getCallingUserId());
     }
 
     public final int startActivityAsUser(IApplicationThread caller,
@@ -2320,20 +2340,20 @@
             String resultWho, int requestCode, int startFlags,
             String profileFile, ParcelFileDescriptor profileFd, Bundle options, int userId) {
         enforceNotIsolatedCaller("startActivity");
-        if (userId != UserId.getCallingUserId()) {
+        if (userId != UserHandle.getCallingUserId()) {
             // Requesting a different user, make sure that they have the permission
             if (checkComponentPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                     Binder.getCallingPid(), Binder.getCallingUid(), -1, true)
                     == PackageManager.PERMISSION_GRANTED) {
                 // Translate to the current user id, if caller wasn't aware
-                if (userId == UserId.USER_CURRENT) {
+                if (userId == UserHandle.USER_CURRENT) {
                     userId = mCurrentUserId;
                 }
             } else {
                 String msg = "Permission Denial: "
                         + "Request to startActivity as user " + userId
-                        + " but is calling from user " + UserId.getCallingUserId()
+                        + " but is calling from user " + UserHandle.getCallingUserId()
                         + "; this requires "
                         + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
                 Slog.w(TAG, msg);
@@ -2445,7 +2465,7 @@
                     AppGlobals.getPackageManager().queryIntentActivities(
                             intent, r.resolvedType,
                             PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS,
-                            UserId.getCallingUserId());
+                            UserHandle.getCallingUserId());
 
                 // Look for the original activity in the list...
                 final int N = resolves != null ? resolves.size() : 0;
@@ -2517,7 +2537,6 @@
         
         // This is so super not safe, that only the system (or okay root)
         // can do it.
-        int userId = Binder.getOrigCallingUser();
         final int callingUid = Binder.getCallingUid();
         if (callingUid != 0 && callingUid != Process.myUid()) {
             throw new SecurityException(
@@ -2526,7 +2545,7 @@
 
         int ret = mMainStack.startActivityMayWait(null, uid, intent, resolvedType,
                 resultTo, resultWho, requestCode, startFlags,
-                null, null, null, null, options, userId);
+                null, null, null, null, options, UserHandle.getUserId(uid));
         return ret;
     }
 
@@ -2550,7 +2569,7 @@
                     "startActivityInPackage only available to the system");
         }
         int ret = mMainStack.startActivities(null, uid, intents, resolvedTypes, resultTo,
-                options, UserId.getUserId(uid));
+                options, UserHandle.getUserId(uid));
         return ret;
     }
 
@@ -3022,7 +3041,12 @@
         File tracesFile = new File(tracesPath);
         try {
             File tracesDir = tracesFile.getParentFile();
-            if (!tracesDir.exists()) tracesFile.mkdirs();
+            if (!tracesDir.exists()) {
+                tracesFile.mkdirs();
+                if (!SELinux.restorecon(tracesDir)) {
+                    return null;
+                }
+            }
             FileUtils.setPermissions(tracesDir.getPath(), 0775, -1, -1);  // drwxrwxr-x
 
             if (clearTraces && tracesFile.exists()) tracesFile.delete();
@@ -3126,7 +3150,12 @@
             final File tracesDir = tracesFile.getParentFile();
             final File tracesTmp = new File(tracesDir, "__tmp__");
             try {
-                if (!tracesDir.exists()) tracesFile.mkdirs();
+                if (!tracesDir.exists()) {
+                    tracesFile.mkdirs();
+                    if (!SELinux.restorecon(tracesDir.getPath())) {
+                        return;
+                    }
+                }
                 FileUtils.setPermissions(tracesDir.getPath(), 0775, -1, -1);  // drwxrwxr-x
 
                 if (tracesFile.exists()) {
@@ -3416,7 +3445,7 @@
             throw new SecurityException(msg);
         }
         
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
         long callingId = Binder.clearCallingIdentity();
         try {
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -3490,7 +3519,7 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        final int userId = UserId.getCallingUserId();
+        final int userId = UserHandle.getCallingUserId();
         long callingId = Binder.clearCallingIdentity();
         try {
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -3626,7 +3655,7 @@
     }
 
     private void forceStopPackageLocked(final String packageName, int uid) {
-        forceStopPackageLocked(packageName, uid, false, false, true, false, UserId.getUserId(uid));
+        forceStopPackageLocked(packageName, uid, false, false, true, false, UserHandle.getUserId(uid));
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
                 Uri.fromParts("package", packageName, null));
         if (!mProcessesReady) {
@@ -3636,7 +3665,7 @@
         broadcastIntentLocked(null, null, intent,
                 null, null, 0, null, null, null,
                 false, false,
-                MY_PID, Process.SYSTEM_UID, UserId.getUserId(uid));
+                MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(uid));
     }
     
     private final boolean killPackageProcessesLocked(String packageName, int uid,
@@ -4357,8 +4386,8 @@
             try {
                 if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
                     int uid = AppGlobals.getPackageManager()
-                            .getPackageUid(packageName, UserId.getUserId(callingUid));
-                    if (!UserId.isSameApp(callingUid, uid)) {
+                            .getPackageUid(packageName, UserHandle.getUserId(callingUid));
+                    if (!UserHandle.isSameApp(callingUid, uid)) {
                         String msg = "Permission Denial: getIntentSender() from pid="
                             + Binder.getCallingPid()
                             + ", uid=" + Binder.getCallingUid()
@@ -4454,8 +4483,8 @@
             PendingIntentRecord rec = (PendingIntentRecord)sender;
             try {
                 int uid = AppGlobals.getPackageManager()
-                        .getPackageUid(rec.key.packageName, UserId.getCallingUserId());
-                if (!UserId.isSameApp(uid, Binder.getCallingUid())) {
+                        .getPackageUid(rec.key.packageName, UserHandle.getCallingUserId());
+                if (!UserHandle.isSameApp(uid, Binder.getCallingUid())) {
                     String msg = "Permission Denial: cancelIntentSender() from pid="
                         + Binder.getCallingPid()
                         + ", uid=" + Binder.getCallingUid()
@@ -4674,7 +4703,7 @@
         if (permission == null) {
             return PackageManager.PERMISSION_DENIED;
         }
-        return checkComponentPermission(permission, pid, UserId.getAppId(uid), -1, true);
+        return checkComponentPermission(permission, pid, UserHandle.getAppId(uid), -1, true);
     }
 
     /**
@@ -4684,7 +4713,7 @@
     int checkCallingPermission(String permission) {
         return checkPermission(permission,
                 Binder.getCallingPid(),
-                UserId.getAppId(Binder.getCallingUid()));
+                UserHandle.getAppId(Binder.getCallingUid()));
     }
 
     /**
@@ -4815,7 +4844,7 @@
             pid = tlsIdentity.pid;
         }
 
-        uid = UserId.getAppId(uid);
+        uid = UserHandle.getAppId(uid);
         // Our own process gets to do everything.
         if (pid == MY_PID) {
             return PackageManager.PERMISSION_GRANTED;
@@ -4861,13 +4890,13 @@
         String name = uri.getAuthority();
         ProviderInfo pi = null;
         ContentProviderRecord cpr = mProviderMap.getProviderByName(name,
-                UserId.getUserId(callingUid));
+                UserHandle.getUserId(callingUid));
         if (cpr != null) {
             pi = cpr.info;
         } else {
             try {
                 pi = pm.resolveContentProvider(name,
-                        PackageManager.GET_URI_PERMISSION_PATTERNS, UserId.getUserId(callingUid));
+                        PackageManager.GET_URI_PERMISSION_PATTERNS, UserHandle.getUserId(callingUid));
             } catch (RemoteException ex) {
             }
         }
@@ -4879,7 +4908,7 @@
         int targetUid = lastTargetUid;
         if (targetUid < 0 && targetPkg != null) {
             try {
-                targetUid = pm.getPackageUid(targetPkg, UserId.getUserId(callingUid));
+                targetUid = pm.getPackageUid(targetPkg, UserHandle.getUserId(callingUid));
                 if (targetUid < 0) {
                     if (DEBUG_URI_PERMISSION) Slog.v(TAG,
                             "Can't grant URI permission no uid for: " + targetPkg);
@@ -5171,7 +5200,7 @@
 
         final String authority = uri.getAuthority();
         ProviderInfo pi = null;
-        int userId = UserId.getUserId(callingUid);
+        int userId = UserHandle.getUserId(callingUid);
         ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userId);
         if (cpr != null) {
             pi = cpr.info;
@@ -5509,7 +5538,7 @@
     public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
             int flags, int userId) {
         final int callingUid = Binder.getCallingUid();
-        if (userId != UserId.getCallingUserId()) {
+        if (userId != UserHandle.getCallingUserId()) {
             // Check if the caller is holding permissions for cross-user requests.
             if (checkComponentPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
@@ -5517,13 +5546,13 @@
                     != PackageManager.PERMISSION_GRANTED) {
                 String msg = "Permission Denial: "
                         + "Request to get recent tasks for user " + userId
-                        + " but is calling from user " + UserId.getUserId(callingUid)
+                        + " but is calling from user " + UserHandle.getUserId(callingUid)
                         + "; this requires "
                         + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
                 Slog.w(TAG, msg);
                 throw new SecurityException(msg);
             } else {
-                if (userId == UserId.USER_CURRENT) {
+                if (userId == UserHandle.USER_CURRENT) {
                     userId = mCurrentUserId;
                 }
             }
@@ -5994,7 +6023,7 @@
                     (ProviderInfo)providers.get(i);
                 boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
                         cpi.name, cpi.flags);
-                if (singleton && UserId.getUserId(app.uid) != 0) {
+                if (singleton && UserHandle.getUserId(app.uid) != 0) {
                     // This is a singleton provider, but a user besides the
                     // default user is asking to initialize a process it runs
                     // in...  well, no, it doesn't actually run in this process,
@@ -6165,7 +6194,7 @@
             }
 
             // First check if this content provider has been published...
-            int userId = UserId.getUserId(r != null ? r.uid : Binder.getCallingUid());
+            int userId = UserHandle.getUserId(r != null ? r.uid : Binder.getCallingUid());
             cpr = mProviderMap.getProviderByName(name, userId);
             boolean providerRunning = cpr != null;
             if (providerRunning) {
@@ -6713,7 +6742,7 @@
         BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
         int uid = info.uid;
         if (isolated) {
-            int userId = UserId.getUserId(uid);
+            int userId = UserHandle.getUserId(uid);
             int stepsLeft = Process.LAST_ISOLATED_UID - Process.FIRST_ISOLATED_UID + 1;
             uid = 0;
             while (true) {
@@ -6721,7 +6750,7 @@
                         || mNextIsolatedProcessUid > Process.LAST_ISOLATED_UID) {
                     mNextIsolatedProcessUid = Process.FIRST_ISOLATED_UID;
                 }
-                uid = UserId.getUid(userId, mNextIsolatedProcessUid);
+                uid = UserHandle.getUid(userId, mNextIsolatedProcessUid);
                 mNextIsolatedProcessUid++;
                 if (mIsolatedProcesses.indexOfKey(uid) < 0) {
                     // No process for this uid, use it.
@@ -6759,7 +6788,7 @@
         // This package really, really can not be stopped.
         try {
             AppGlobals.getPackageManager().setPackageStoppedState(
-                    info.packageName, false, UserId.getUserId(app.uid));
+                    info.packageName, false, UserHandle.getUserId(app.uid));
         } catch (RemoteException e) {
         } catch (IllegalArgumentException e) {
             Slog.w(TAG, "Failed trying to unstop package "
@@ -8370,11 +8399,19 @@
         // assume our apps are happy - lazy create the list
         List<ActivityManager.ProcessErrorStateInfo> errList = null;
 
+        final boolean allUsers = ActivityManager.checkUidPermission(
+                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                Binder.getCallingUid()) == PackageManager.PERMISSION_GRANTED;
+        int userId = UserHandle.getUserId(Binder.getCallingUid());
+
         synchronized (this) {
 
             // iterate across all processes
             for (int i=mLruProcesses.size()-1; i>=0; i--) {
                 ProcessRecord app = mLruProcesses.get(i);
+                if (!allUsers && app.userId != userId) {
+                    continue;
+                }
                 if ((app.thread != null) && (app.crashing || app.notResponding)) {
                     // This one's in trouble, so we'll generate a report for it
                     // crashes are higher priority (in case there's a crash *and* an anr)
@@ -8438,6 +8475,9 @@
         if (app.persistent) {
             outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT;
         }
+        if (app.hasActivities) {
+            outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_HAS_ACTIVITIES;
+        }
         outInfo.lastTrimLevel = app.trimMemoryLevel;
         int adj = app.curAdj;
         outInfo.importance = oomAdjToImportance(adj, outInfo);
@@ -8448,10 +8488,17 @@
         enforceNotIsolatedCaller("getRunningAppProcesses");
         // Lazy instantiation of list
         List<ActivityManager.RunningAppProcessInfo> runList = null;
+        final boolean allUsers = ActivityManager.checkUidPermission(
+                android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                Binder.getCallingUid()) == PackageManager.PERMISSION_GRANTED;
+        int userId = UserHandle.getUserId(Binder.getCallingUid());
         synchronized (this) {
             // Iterate across all processes
             for (int i=mLruProcesses.size()-1; i>=0; i--) {
                 ProcessRecord app = mLruProcesses.get(i);
+                if (!allUsers && app.userId != userId) {
+                    continue;
+                }
                 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
                     // Generate process state info for running application
                     ActivityManager.RunningAppProcessInfo currApp = 
@@ -8497,7 +8544,7 @@
             IPackageManager pm = AppGlobals.getPackageManager();
             for (String pkg : extList) {
                 try {
-                    ApplicationInfo info = pm.getApplicationInfo(pkg, 0, UserId.getCallingUserId());
+                    ApplicationInfo info = pm.getApplicationInfo(pkg, 0, UserHandle.getCallingUserId());
                     if ((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
                         retList.add(info);
                     }
@@ -9081,7 +9128,9 @@
             pw.println("  mGoingToSleep=" + mMainStack.mGoingToSleep);
             pw.println("  mLaunchingActivity=" + mMainStack.mLaunchingActivity);
             pw.println("  mAdjSeq=" + mAdjSeq + " mLruSeq=" + mLruSeq);
-            pw.println("  mNumServiceProcs=" + mNumServiceProcs
+            pw.println("  mNumNonHiddenProcs=" + mNumNonHiddenProcs
+                    + " mNumHiddenProcs=" + mNumHiddenProcs
+                    + " mNumServiceProcs=" + mNumServiceProcs
                     + " mNewNumServiceProcs=" + mNewNumServiceProcs);
         }
         
@@ -9746,6 +9795,7 @@
                 pw.print("    ");
                 pw.print("oom: max="); pw.print(r.maxAdj);
                 pw.print(" hidden="); pw.print(r.hiddenAdj);
+                pw.print(" empty="); pw.print(r.emptyAdj);
                 pw.print(" curRaw="); pw.print(r.curRawAdj);
                 pw.print(" setRaw="); pw.print(r.setRawAdj);
                 pw.print(" cur="); pw.print(r.curAdj);
@@ -10243,10 +10293,10 @@
                 cpr.launchingApp = null;
                 cpr.notifyAll();
             }
-            mProviderMap.removeProviderByClass(cpr.name, UserId.getUserId(cpr.uid));
+            mProviderMap.removeProviderByClass(cpr.name, UserHandle.getUserId(cpr.uid));
             String names[] = cpr.info.authority.split(";");
             for (int j = 0; j < names.length; j++) {
-                mProviderMap.removeProviderByName(names[j], UserId.getUserId(cpr.uid));
+                mProviderMap.removeProviderByName(names[j], UserHandle.getUserId(cpr.uid));
             }
         }
 
@@ -10584,7 +10634,7 @@
     boolean isSingleton(String componentProcessName, ApplicationInfo aInfo,
             String className, int flags) {
         boolean result = false;
-        if (UserId.getAppId(aInfo.uid) >= Process.FIRST_APPLICATION_UID) {
+        if (UserHandle.getAppId(aInfo.uid) >= Process.FIRST_APPLICATION_UID) {
             if ((flags&ServiceInfo.FLAG_SINGLE_USER) != 0) {
                 if (ActivityManager.checkUidPermission(
                         android.Manifest.permission.INTERACT_ACROSS_USERS,
@@ -10689,7 +10739,7 @@
             // Backup agent is now in use, its package can't be stopped.
             try {
                 AppGlobals.getPackageManager().setPackageStoppedState(
-                        app.packageName, false, UserId.getUserId(app.uid));
+                        app.packageName, false, UserHandle.getUserId(app.uid));
             } catch (RemoteException e) {
             } catch (IllegalArgumentException e) {
                 Slog.w(TAG, "Failed trying to unstop package "
@@ -11031,7 +11081,7 @@
 
         // If the caller is trying to send this broadcast to a different
         // user, verify that is allowed.
-        if (UserId.getUserId(callingUid) != userId) {
+        if (UserHandle.getUserId(callingUid) != userId) {
             if (checkComponentPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                     callingPid, callingUid, -1, true)
@@ -11045,7 +11095,7 @@
                     String msg = "Permission Denial: " + intent.getAction()
                             + " broadcast from " + callerPackage
                             + " asks to send as user " + userId
-                            + " but is calling from user " + UserId.getUserId(callingUid)
+                            + " but is calling from user " + UserHandle.getUserId(callingUid)
                             + "; this requires "
                             + android.Manifest.permission.INTERACT_ACROSS_USERS;
                     Slog.w(TAG, msg);
@@ -11538,7 +11588,7 @@
                 throw new SecurityException(msg);
             }
 
-            int userId = UserId.getCallingUserId();
+            int userId = UserHandle.getCallingUserId();
             final long origId = Binder.clearCallingIdentity();
             // Instrumentation can kill and relaunch even persistent processes
             forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, userId);
@@ -11601,7 +11651,7 @@
 
     public void finishInstrumentation(IApplicationThread target,
             int resultCode, Bundle results) {
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
         // Refuse possible leaked file descriptors
         if (results != null && results.hasFileDescriptors()) {
             throw new IllegalArgumentException("File descriptors passed in Intent");
@@ -11914,7 +11964,7 @@
                 } else {
                     try {
                         ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
-                                destIntent.getComponent(), 0, UserId.getCallingUserId());
+                                destIntent.getComponent(), 0, UserHandle.getCallingUserId());
                         int res = mMainStack.startActivityLocked(srec.app.thread, destIntent,
                                 null, aInfo, parent.appToken, null,
                                 0, -1, parent.launchedFromUid, 0, null, true, null);
@@ -11966,14 +12016,15 @@
     }
 
     private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
-            ProcessRecord TOP_APP, boolean recursed, boolean doingAll) {
+            int emptyAdj, ProcessRecord TOP_APP, boolean recursed, boolean doingAll) {
         if (mAdjSeq == app.adjSeq) {
             // This adjustment has already been computed.  If we are calling
             // from the top, we may have already computed our adjustment with
             // an earlier hidden adjustment that isn't really for us... if
             // so, use the new hidden adjustment.
             if (!recursed && app.hidden) {
-                app.curAdj = app.curRawAdj = app.nonStoppingAdj = hiddenAdj;
+                app.curAdj = app.curRawAdj = app.nonStoppingAdj =
+                        app.hasActivities ? hiddenAdj : emptyAdj;
             }
             return app.curRawAdj;
         }
@@ -11981,7 +12032,7 @@
         if (app.thread == null) {
             app.adjSeq = mAdjSeq;
             app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
-            return (app.curAdj=ProcessList.HIDDEN_APP_MAX_ADJ);
+            return (app.curAdj=app.curRawAdj=ProcessList.HIDDEN_APP_MAX_ADJ);
         }
 
         app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
@@ -11998,6 +12049,7 @@
             app.adjType = "fixed";
             app.adjSeq = mAdjSeq;
             app.curRawAdj = app.nonStoppingAdj = app.maxAdj;
+            app.hasActivities = false;
             app.foregroundActivities = false;
             app.keeping = true;
             app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
@@ -12008,12 +12060,15 @@
             app.systemNoUi = true;
             if (app == TOP_APP) {
                 app.systemNoUi = false;
+                app.hasActivities = true;
             } else if (activitiesSize > 0) {
                 for (int j = 0; j < activitiesSize; j++) {
                     final ActivityRecord r = app.activities.get(j);
                     if (r.visible) {
                         app.systemNoUi = false;
-                        break;
+                    }
+                    if (r.app == app) {
+                        app.hasActivities = true;
                     }
                 }
             }
@@ -12022,6 +12077,7 @@
 
         app.keeping = false;
         app.systemNoUi = false;
+        app.hasActivities = false;
 
         // Determine the importance of the process, starting with most
         // important to least, and assign an appropriate OOM adjustment.
@@ -12037,6 +12093,7 @@
             app.adjType = "top-activity";
             foregroundActivities = true;
             interesting = true;
+            app.hasActivities = true;
         } else if (app.instrumentationClass != null) {
             // Don't want to kill running instrumentation.
             adj = ProcessList.FOREGROUND_APP_ADJ;
@@ -12058,21 +12115,13 @@
             adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "exec-service";
-        } else if (activitiesSize > 0) {
-            // This app is in the background with paused activities.
-            // We inspect activities to potentially upgrade adjustment further below.
+        } else {
+            // Assume process is hidden (has activities); we will correct
+            // later if this is not the case.
             adj = hiddenAdj;
             schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
             app.hidden = true;
             app.adjType = "bg-activities";
-        } else {
-            // A very not-needed process.  If this is lower in the lru list,
-            // we will push it in to the empty bucket.
-            adj = hiddenAdj;
-            schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
-            app.hidden = true;
-            app.empty = true;
-            app.adjType = "bg-empty";
         }
 
         boolean hasStoppingActivities = false;
@@ -12089,6 +12138,7 @@
                     }
                     schedGroup = Process.THREAD_GROUP_DEFAULT;
                     app.hidden = false;
+                    app.hasActivities = true;
                     foregroundActivities = true;
                     break;
                 } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED) {
@@ -12106,9 +12156,20 @@
                     foregroundActivities = true;
                     hasStoppingActivities = true;
                 }
+                if (r.app == app) {
+                    app.hasActivities = true;
+                }
             }
         }
 
+        if (adj == hiddenAdj && !app.hasActivities) {
+            // Whoops, this process is completely empty as far as we know
+            // at this point.
+            adj = emptyAdj;
+            app.empty = true;
+            app.adjType = "bg-empty";
+        }
+
         if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
             if (app.foregroundServices) {
                 // The user is aware of this app, so make it visible.
@@ -12242,8 +12303,16 @@
                                         myHiddenAdj = ProcessList.VISIBLE_APP_ADJ;
                                     }
                                 }
-                                clientAdj = computeOomAdjLocked(
-                                    client, myHiddenAdj, TOP_APP, true, doingAll);
+                                int myEmptyAdj = emptyAdj;
+                                if (myEmptyAdj > client.emptyAdj) {
+                                    if (client.emptyAdj >= ProcessList.VISIBLE_APP_ADJ) {
+                                        myEmptyAdj = client.emptyAdj;
+                                    } else {
+                                        myEmptyAdj = ProcessList.VISIBLE_APP_ADJ;
+                                    }
+                                }
+                                clientAdj = computeOomAdjLocked(client, myHiddenAdj,
+                                        myEmptyAdj, TOP_APP, true, doingAll);
                                 String adjType = null;
                                 if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
                                     // Not doing bind OOM management, so treat
@@ -12382,8 +12451,16 @@
                             myHiddenAdj = ProcessList.FOREGROUND_APP_ADJ;
                         }
                     }
-                    int clientAdj = computeOomAdjLocked(
-                        client, myHiddenAdj, TOP_APP, true, doingAll);
+                    int myEmptyAdj = emptyAdj;
+                    if (myEmptyAdj > client.emptyAdj) {
+                        if (client.emptyAdj > ProcessList.FOREGROUND_APP_ADJ) {
+                            myEmptyAdj = client.emptyAdj;
+                        } else {
+                            myEmptyAdj = ProcessList.FOREGROUND_APP_ADJ;
+                        }
+                    }
+                    int clientAdj = computeOomAdjLocked(client, myHiddenAdj,
+                            myEmptyAdj, TOP_APP, true, doingAll);
                     if (adj > clientAdj) {
                         if (app.hasShownUi && app != mHomeProcess
                                 && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -12796,9 +12873,10 @@
         }
     }
 
-    private final boolean updateOomAdjLocked(
-            ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP, boolean doingAll) {
+    private final boolean updateOomAdjLocked(ProcessRecord app, int hiddenAdj,
+            int emptyAdj, ProcessRecord TOP_APP, boolean doingAll) {
         app.hiddenAdj = hiddenAdj;
+        app.emptyAdj = emptyAdj;
 
         if (app.thread == null) {
             return false;
@@ -12808,7 +12886,7 @@
 
         boolean success = true;
 
-        computeOomAdjLocked(app, hiddenAdj, TOP_APP, false, doingAll);
+        computeOomAdjLocked(app, hiddenAdj, emptyAdj, TOP_APP, false, doingAll);
 
         if (app.curRawAdj != app.setRawAdj) {
             if (wasKeeping && !app.keeping) {
@@ -12895,7 +12973,8 @@
 
         mAdjSeq++;
 
-        boolean success = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP, false);
+        boolean success = updateOomAdjLocked(app, app.hiddenAdj, app.emptyAdj,
+                TOP_APP, false);
         final boolean nowHidden = app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ
             && app.curAdj <= ProcessList.HIDDEN_APP_MAX_ADJ;
         if (nowHidden != wasHidden) {
@@ -12923,34 +13002,53 @@
         // how many slots we have for background processes; we may want
         // to put multiple processes in a slot of there are enough of
         // them.
-        int numSlots = ProcessList.HIDDEN_APP_MAX_ADJ - ProcessList.HIDDEN_APP_MIN_ADJ + 1;
-        int factor = (mLruProcesses.size()-4)/numSlots;
-        if (factor < 1) factor = 1;
-        int step = 0;
+        int numSlots = (ProcessList.HIDDEN_APP_MAX_ADJ
+                - ProcessList.HIDDEN_APP_MIN_ADJ + 1) / 2;
+        int emptyFactor = (mLruProcesses.size()-mNumNonHiddenProcs-mNumHiddenProcs)/numSlots;
+        if (emptyFactor < 1) emptyFactor = 1;
+        int hiddenFactor = (mNumHiddenProcs > 0 ? mNumHiddenProcs : 1)/numSlots;
+        if (hiddenFactor < 1) hiddenFactor = 1;
+        int stepHidden = 0;
+        int stepEmpty = 0;
+        final int emptyProcessLimit = mProcessLimit > 1 ? mProcessLimit / 2 : mProcessLimit;
+        final int hiddenProcessLimit = mProcessLimit > 1 ? mProcessLimit / 2 : mProcessLimit;
         int numHidden = 0;
+        int numEmpty = 0;
         int numTrimming = 0;
-        
+
+        mNumNonHiddenProcs = 0;
+        mNumHiddenProcs = 0;
+
         // First update the OOM adjustment for each of the
         // application processes based on their current state.
         int i = mLruProcesses.size();
         int curHiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
+        int nextHiddenAdj = curHiddenAdj+1;
+        int curEmptyAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
+        int nextEmptyAdj = curEmptyAdj+2;
         while (i > 0) {
             i--;
             ProcessRecord app = mLruProcesses.get(i);
             //Slog.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
-            updateOomAdjLocked(app, curHiddenAdj, TOP_APP, true);
-            if (curHiddenAdj < ProcessList.HIDDEN_APP_MAX_ADJ
-                && app.curAdj == curHiddenAdj) {
-                step++;
-                if (step >= factor) {
-                    step = 0;
-                    curHiddenAdj++;
-                }
-            }
+            updateOomAdjLocked(app, curHiddenAdj, curEmptyAdj, TOP_APP, true);
             if (!app.killedBackground) {
-                if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
+                if (app.curRawAdj == curHiddenAdj && app.hasActivities) {
+                    // This process was assigned as a hidden process...  step the
+                    // hidden level.
+                    mNumHiddenProcs++;
+                    if (curHiddenAdj != nextHiddenAdj) {
+                        stepHidden++;
+                        if (stepHidden >= hiddenFactor) {
+                            stepHidden = 0;
+                            curHiddenAdj = nextHiddenAdj;
+                            nextHiddenAdj += 2;
+                            if (nextHiddenAdj > ProcessList.HIDDEN_APP_MAX_ADJ) {
+                                nextHiddenAdj = ProcessList.HIDDEN_APP_MAX_ADJ;
+                            }
+                        }
+                    }
                     numHidden++;
-                    if (numHidden > mProcessLimit) {
+                    if (numHidden > hiddenProcessLimit) {
                         Slog.i(TAG, "No longer want " + app.processName
                                 + " (pid " + app.pid + "): hidden #" + numHidden);
                         EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
@@ -12958,8 +13056,37 @@
                         app.killedBackground = true;
                         Process.killProcessQuiet(app.pid);
                     }
+                } else {
+                    if (app.curRawAdj == curEmptyAdj || app.curRawAdj == curHiddenAdj) {
+                        // This process was assigned as an empty process...  step the
+                        // empty level.
+                        if (curEmptyAdj != nextEmptyAdj) {
+                            stepEmpty++;
+                            if (stepEmpty >= emptyFactor) {
+                                stepEmpty = 0;
+                                curEmptyAdj = nextEmptyAdj;
+                                nextEmptyAdj += 2;
+                                if (nextEmptyAdj > ProcessList.HIDDEN_APP_MAX_ADJ) {
+                                    nextEmptyAdj = ProcessList.HIDDEN_APP_MAX_ADJ;
+                                }
+                            }
+                        }
+                    } else if (app.curRawAdj < ProcessList.HIDDEN_APP_MIN_ADJ) {
+                        mNumNonHiddenProcs++;
+                    }
+                    if (app.curAdj >= ProcessList.HIDDEN_APP_MIN_ADJ) {
+                        numEmpty++;
+                        if (numEmpty > emptyProcessLimit) {
+                            Slog.i(TAG, "No longer want " + app.processName
+                                    + " (pid " + app.pid + "): empty #" + numEmpty);
+                            EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+                                    app.processName, app.setAdj, "too many background");
+                            app.killedBackground = true;
+                            Process.killProcessQuiet(app.pid);
+                        }
+                    }
                 }
-                if (!app.killedBackground && app.isolated && app.services.size() <= 0) {
+                if (app.isolated && app.services.size() <= 0) {
                     // If this is an isolated process, and there are no
                     // services running in it, then the process is no longer
                     // needed.  We agressively kill these because we can by
@@ -12989,18 +13116,20 @@
         // are managing to keep around is less than half the maximum we desire;
         // if we are keeping a good number around, we'll let them use whatever
         // memory they want.
-        if (numHidden <= (ProcessList.MAX_HIDDEN_APPS/2)) {
+        if (numHidden <= (ProcessList.MAX_HIDDEN_APPS/4)
+                && numEmpty <= (ProcessList.MAX_HIDDEN_APPS/4)) {
+            final int numHiddenAndEmpty = numHidden + numEmpty;
             final int N = mLruProcesses.size();
-            factor = numTrimming/3;
+            int factor = numTrimming/3;
             int minFactor = 2;
             if (mHomeProcess != null) minFactor++;
             if (mPreviousProcess != null) minFactor++;
             if (factor < minFactor) factor = minFactor;
-            step = 0;
+            int step = 0;
             int fgTrimLevel;
-            if (numHidden <= (ProcessList.MAX_HIDDEN_APPS/5)) {
+            if (numHiddenAndEmpty <= (ProcessList.MAX_HIDDEN_APPS/5)) {
                 fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
-            } else if (numHidden <= (ProcessList.MAX_HIDDEN_APPS/3)) {
+            } else if (numHiddenAndEmpty <= (ProcessList.MAX_HIDDEN_APPS/3)) {
                 fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
             } else {
                 fgTrimLevel = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
@@ -13388,8 +13517,8 @@
 
         // Inform of user switch
         Intent addedIntent = new Intent(Intent.ACTION_USER_SWITCHED);
-        addedIntent.putExtra(Intent.EXTRA_USERID, userId);
-        mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS);
+        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+        mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_USERS);
 
         return true;
     }
@@ -13405,7 +13534,7 @@
     }
 
     private void onUserRemoved(Intent intent) {
-        int extraUserId = intent.getIntExtra(Intent.EXTRA_USERID, -1);
+        int extraUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
         if (extraUserId < 1) return;
 
         // Kill all the processes for the user
@@ -13415,7 +13544,7 @@
             for (Entry<String, SparseArray<ProcessRecord>> uidMap : map.entrySet()) {
                 SparseArray<ProcessRecord> uids = uidMap.getValue();
                 for (int i = 0; i < uids.size(); i++) {
-                    if (UserId.getUserId(uids.keyAt(i)) == extraUserId) {
+                    if (UserHandle.getUserId(uids.keyAt(i)) == extraUserId) {
                         pkgAndUids.add(new Pair<String,Integer>(uidMap.getKey(), uids.keyAt(i)));
                     }
                 }
@@ -13441,14 +13570,14 @@
     }
 
     private void checkValidCaller(int uid, int userId) {
-        if (UserId.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0) return;
+        if (UserHandle.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0) return;
 
         throw new SecurityException("Caller uid=" + uid
                 + " is not privileged to communicate with user=" + userId);
     }
 
     private int applyUserId(int uid, int userId) {
-        return UserId.getUid(userId, uid);
+        return UserHandle.getUid(userId, uid);
     }
 
     ApplicationInfo getAppInfoForUser(ApplicationInfo info, int userId) {
@@ -13462,7 +13591,7 @@
 
     ActivityInfo getActivityInfoForUser(ActivityInfo aInfo, int userId) {
         if (aInfo == null
-                || (userId < 1 && aInfo.applicationInfo.uid < UserId.PER_USER_RANGE)) {
+                || (userId < 1 && aInfo.applicationInfo.uid < UserHandle.PER_USER_RANGE)) {
             return aInfo;
         }
 
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index c40abb7..c70650d 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -37,7 +37,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
@@ -321,7 +321,7 @@
         appToken = new Token(this);
         info = aInfo;
         launchedFromUid = _launchedFromUid;
-        userId = UserId.getUserId(aInfo.applicationInfo.uid);
+        userId = UserHandle.getUserId(aInfo.applicationInfo.uid);
         intent = _intent;
         shortComponentName = _intent.getComponent().flattenToShortString();
         resolvedType = _resolvedType;
@@ -614,14 +614,14 @@
                                 pendingOptions.getStartY()+pendingOptions.getStartHeight()));
                     }
                     break;
-                case ActivityOptions.ANIM_THUMBNAIL:
-                case ActivityOptions.ANIM_THUMBNAIL_DELAYED:
-                    boolean delayed = (animationType == ActivityOptions.ANIM_THUMBNAIL_DELAYED);
+                case ActivityOptions.ANIM_THUMBNAIL_SCALE_UP:
+                case ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN:
+                    boolean scaleUp = (animationType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP);
                     service.mWindowManager.overridePendingAppTransitionThumb(
                             pendingOptions.getThumbnail(),
                             pendingOptions.getStartX(), pendingOptions.getStartY(),
                             pendingOptions.getOnAnimationStartListener(),
-                            delayed);
+                            scaleUp);
                     if (intent.getSourceBounds() == null) {
                         intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
                                 pendingOptions.getStartY(),
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 196a259..ccea41a 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -55,7 +55,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
@@ -501,7 +501,7 @@
 
         TaskRecord cp = null;
 
-        final int userId = UserId.getUserId(info.applicationInfo.uid);
+        final int userId = UserHandle.getUserId(info.applicationInfo.uid);
         final int N = mHistory.size();
         for (int i=(N-1); i>=0; i--) {
             ActivityRecord r = mHistory.get(i);
@@ -545,7 +545,7 @@
         if (info.targetActivity != null) {
             cls = new ComponentName(info.packageName, info.targetActivity);
         }
-        final int userId = UserId.getUserId(info.applicationInfo.uid);
+        final int userId = UserHandle.getUserId(info.applicationInfo.uid);
 
         final int N = mHistory.size();
         for (int i=(N-1); i>=0; i--) {
@@ -2406,7 +2406,7 @@
         }
 
         if (err == ActivityManager.START_SUCCESS) {
-            final int userId = aInfo != null ? UserId.getUserId(aInfo.applicationInfo.uid) : 0;
+            final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
             Slog.i(TAG, "START {" + intent.toShortString(true, true, true, false)
                     + " u=" + userId + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
         }
@@ -3014,8 +3014,8 @@
         // Collect information about the target of the Intent.
         ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
                 profileFile, profileFd, userId);
-        if (aInfo != null && mService.isSingleton(aInfo.processName, aInfo.applicationInfo,
-                null, 0)) {
+        if (aInfo != null && (aInfo.flags & ActivityInfo.FLAG_MULTIPROCESS) == 0
+                && mService.isSingleton(aInfo.processName, aInfo.applicationInfo, null, 0)) {
             userId = 0;
         }
         aInfo = mService.getActivityInfoForUser(aInfo, userId);
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index 76ddb96..7873dd8 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -36,7 +36,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.EventLog;
 import android.util.Slog;
 
@@ -373,7 +373,7 @@
             BroadcastFilter filter, boolean ordered) {
         boolean skip = false;
         if (r.onlySendToCaller) {
-            if (!UserId.isSameApp(r.callingUid, filter.owningUid)) {
+            if (!UserHandle.isSameApp(r.callingUid, filter.owningUid)) {
                 Slog.w(TAG, "Permission Denial: broadcasting "
                         + r.intent.toString()
                         + " from " + r.callerPackage + " (pid="
@@ -668,7 +668,7 @@
 
             boolean skip = false;
             if (r.onlySendToCaller) {
-                if (!UserId.isSameApp(r.callingUid, info.activityInfo.applicationInfo.uid)) {
+                if (!UserHandle.isSameApp(r.callingUid, info.activityInfo.applicationInfo.uid)) {
                     Slog.w(TAG, "Permission Denial: broadcasting "
                             + r.intent.toString()
                             + " from " + r.callerPackage + " (pid="
@@ -766,7 +766,7 @@
                 info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
             }
             r.curReceiver = info.activityInfo;
-            if (DEBUG_MU && r.callingUid > UserId.PER_USER_RANGE) {
+            if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {
                 Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
                         + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
                         + info.activityInfo.applicationInfo.uid);
@@ -775,7 +775,7 @@
             // Broadcast is being executed, its package can't be stopped.
             try {
                 AppGlobals.getPackageManager().setPackageStoppedState(
-                        r.curComponent.getPackageName(), false, UserId.getUserId(r.callingUid));
+                        r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));
             } catch (RemoteException e) {
             } catch (IllegalArgumentException e) {
                 Slog.w(TAG, "Failed trying to unstop package "
diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java
index 0106114..5b3ff8d 100644
--- a/services/java/com/android/server/am/ConnectionRecord.java
+++ b/services/java/com/android/server/am/ConnectionRecord.java
@@ -18,6 +18,7 @@
 
 import android.app.IServiceConnection;
 import android.app.PendingIntent;
+import android.content.Context;
 
 import java.io.PrintWriter;
 
@@ -62,6 +63,33 @@
         sb.append("ConnectionRecord{");
         sb.append(Integer.toHexString(System.identityHashCode(this)));
         sb.append(' ');
+        if ((flags&Context.BIND_AUTO_CREATE) != 0) {
+            sb.append("CR ");
+        }
+        if ((flags&Context.BIND_DEBUG_UNBIND) != 0) {
+            sb.append("DBG ");
+        }
+        if ((flags&Context.BIND_NOT_FOREGROUND) != 0) {
+            sb.append("NOTFG ");
+        }
+        if ((flags&Context.BIND_ABOVE_CLIENT) != 0) {
+            sb.append("ABCLT ");
+        }
+        if ((flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
+            sb.append("OOM ");
+        }
+        if ((flags&Context.BIND_WAIVE_PRIORITY) != 0) {
+            sb.append("WPRI ");
+        }
+        if ((flags&Context.BIND_IMPORTANT) != 0) {
+            sb.append("IMP ");
+        }
+        if ((flags&Context.BIND_ADJUST_WITH_ACTIVITY) != 0) {
+            sb.append("ACT ");
+        }
+        if ((flags&Context.BIND_NOT_VISIBLE) != 0) {
+            sb.append("NOTVIS ");
+        }
         if (serviceDead) {
             sb.append("DEAD ");
         }
diff --git a/services/java/com/android/server/am/DeviceMonitor.java b/services/java/com/android/server/am/DeviceMonitor.java
index 5f3b0ce..21e7252 100644
--- a/services/java/com/android/server/am/DeviceMonitor.java
+++ b/services/java/com/android/server/am/DeviceMonitor.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import android.os.SELinux;
 import android.util.Slog;
 
 import java.io.*;
@@ -80,6 +81,9 @@
         if (!BASE.isDirectory() && !BASE.mkdirs()) {
             throw new AssertionError("Couldn't create " + BASE + ".");
         }
+        if (!SELinux.restorecon(BASE)) {
+            throw new AssertionError("Couldn't restorecon " + BASE + ".");
+        }
     }
 
     private static final File[] PATHS = {
diff --git a/services/java/com/android/server/am/IntentBindRecord.java b/services/java/com/android/server/am/IntentBindRecord.java
index c94f714..0a92964 100644
--- a/services/java/com/android/server/am/IntentBindRecord.java
+++ b/services/java/com/android/server/am/IntentBindRecord.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import android.content.Context;
 import android.content.Intent;
 import android.os.IBinder;
 
@@ -78,6 +79,20 @@
         intent = _intent;
     }
 
+    int collectFlags() {
+        int flags = 0;
+        if (apps.size() > 0) {
+            for (AppBindRecord app : apps.values()) {
+                if (app.connections.size() > 0) {
+                    for (ConnectionRecord conn : app.connections) {
+                        flags |= conn.flags;
+                    }
+                }
+            }
+        }
+        return flags;
+    }
+
     public String toString() {
         if (stringName != null) {
             return stringName;
@@ -86,6 +101,9 @@
         sb.append("IntentBindRecord{");
         sb.append(Integer.toHexString(System.identityHashCode(this)));
         sb.append(' ');
+        if ((collectFlags()&Context.BIND_AUTO_CREATE) != 0) {
+            sb.append("CR ");
+        }
         sb.append(service.shortName);
         sb.append(':');
         if (intent != null) {
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index ad15da1..d3b8510 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -25,7 +25,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.Slog;
 
 import java.io.PrintWriter;
@@ -259,7 +259,7 @@
                             owner.broadcastIntentInPackage(key.packageName, uid,
                                     finalIntent, resolvedType,
                                     finishedReceiver, code, null, null,
-                                requiredPermission, (finishedReceiver != null), false, UserId
+                                requiredPermission, (finishedReceiver != null), false, UserHandle
                                         .getUserId(uid));
                             sendFinish = false;
                         } catch (RuntimeException e) {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index cba9480..d372422 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -30,7 +30,7 @@
 import android.os.IBinder;
 import android.os.Process;
 import android.os.SystemClock;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.PrintWriterPrinter;
 import android.util.TimeUtils;
 
@@ -61,6 +61,7 @@
     long lruWeight;             // Weight for ordering in LRU list
     int maxAdj;                 // Maximum OOM adjustment for this process
     int hiddenAdj;              // If hidden, this is the adjustment to use
+    int emptyAdj;               // If empty, this is the adjustment to use
     int curRawAdj;              // Current OOM unlimited adjustment for this process
     int setRawAdj;              // Last set OOM unlimited adjustment for this process
     int nonStoppingAdj;         // Adjustment not counting any stopping activities
@@ -73,6 +74,7 @@
     boolean serviceb;           // Process currently is on the service B list
     boolean keeping;            // Actively running code so don't kill due to that?
     boolean setIsForeground;    // Running foreground UI when last set?
+    boolean hasActivities;      // Are there any activities running in this process?
     boolean foregroundServices; // Running any services that are foreground?
     boolean foregroundActivities; // Running any activities that are foreground?
     boolean systemNoUi;         // This is a system process, but not currently showing UI.
@@ -199,6 +201,7 @@
                 pw.print(" empty="); pw.println(empty);
         pw.print(prefix); pw.print("oom: max="); pw.print(maxAdj);
                 pw.print(" hidden="); pw.print(hiddenAdj);
+                pw.print(" empty="); pw.print(emptyAdj);
                 pw.print(" curRaw="); pw.print(curRawAdj);
                 pw.print(" setRaw="); pw.print(setRawAdj);
                 pw.print(" nonStopping="); pw.print(nonStoppingAdj);
@@ -215,7 +218,9 @@
                 pw.print(" foregroundServices="); pw.print(foregroundServices);
                 pw.print(" forcingToForeground="); pw.println(forcingToForeground);
         pw.print(prefix); pw.print("persistent="); pw.print(persistent);
-                pw.print(" removed="); pw.println(removed);
+                pw.print(" removed="); pw.print(removed);
+                pw.print(" hasActivities="); pw.print(hasActivities);
+                pw.print(" foregroundActivities="); pw.println(foregroundActivities);
         pw.print(prefix); pw.print("adjSeq="); pw.print(adjSeq);
                 pw.print(" lruSeq="); pw.println(lruSeq);
         if (!keeping) {
@@ -308,12 +313,12 @@
         info = _info;
         isolated = _info.uid != _uid;
         uid = _uid;
-        userId = UserId.getUserId(_uid);
+        userId = UserHandle.getUserId(_uid);
         processName = _processName;
         pkgList.add(_info.packageName);
         thread = _thread;
         maxAdj = ProcessList.HIDDEN_APP_MAX_ADJ;
-        hiddenAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
+        hiddenAdj = emptyAdj = ProcessList.HIDDEN_APP_MIN_ADJ;
         curRawAdj = setRawAdj = -100;
         curAdj = setAdj = -100;
         persistent = false;
@@ -391,7 +396,7 @@
             sb.append(info.uid%Process.FIRST_APPLICATION_UID);
             if (uid != info.uid) {
                 sb.append('i');
-                sb.append(UserId.getAppId(uid) - Process.FIRST_ISOLATED_UID);
+                sb.append(UserHandle.getAppId(uid) - Process.FIRST_ISOLATED_UID);
             }
         }
     }
diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java
index f4d0f9b..15fbb98 100644
--- a/services/java/com/android/server/am/ProviderMap.java
+++ b/services/java/com/android/server/am/ProviderMap.java
@@ -20,7 +20,7 @@
 import android.os.Binder;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -98,7 +98,7 @@
         if (record.singleton) {
             mSingletonByName.put(name, record);
         } else {
-            final int userId = UserId.getUserId(record.appInfo.uid);
+            final int userId = UserHandle.getUserId(record.appInfo.uid);
             getProvidersByName(userId).put(name, record);
         }
     }
@@ -111,7 +111,7 @@
         if (record.singleton) {
             mSingletonByClass.put(name, record);
         } else {
-            final int userId = UserId.getUserId(record.appInfo.uid);
+            final int userId = UserHandle.getUserId(record.appInfo.uid);
             getProvidersByClass(userId).put(name, record);
         }
     }
@@ -127,7 +127,12 @@
                 Slog.i(TAG,
                         "Removing from providersByName name=" + name + " user="
                         + (optionalUserId == -1 ? Binder.getOrigCallingUser() : optionalUserId));
-            getProvidersByName(optionalUserId).remove(name);
+            HashMap<String, ContentProviderRecord> map = getProvidersByName(optionalUserId);
+            // map returned by getProvidersByName wouldn't be null
+            map.remove(name);
+            if (map.size() == 0) {
+                mProvidersByNamePerUser.remove(optionalUserId);
+            }
         }
     }
 
@@ -141,7 +146,12 @@
                 Slog.i(TAG,
                         "Removing from providersByClass name=" + name + " user="
                         + (optionalUserId == -1 ? Binder.getOrigCallingUser() : optionalUserId));
-            getProvidersByClass(optionalUserId).remove(name);
+            HashMap<ComponentName, ContentProviderRecord> map = getProvidersByClass(optionalUserId);
+            // map returned by getProvidersByClass wouldn't be null
+            map.remove(name);
+            if (map.size() == 0) {
+                mProvidersByClassPerUser.remove(optionalUserId);
+            }
         }
     }
 
@@ -198,7 +208,6 @@
 
     void dumpProvidersLocked(PrintWriter pw, boolean dumpAll) {
         if (mSingletonByClass.size() > 0) {
-            pw.println("");
             pw.println("  Published single-user content providers (by class):");
             dumpProvidersByClassLocked(pw, dumpAll, mSingletonByClass);
         }
@@ -206,10 +215,10 @@
         pw.println("");
         for (int i = 0; i < mProvidersByClassPerUser.size(); i++) {
             HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.valueAt(i);
+            pw.println("");
             pw.println("  Published user " + mProvidersByClassPerUser.keyAt(i)
                     + " content providers (by class):");
             dumpProvidersByClassLocked(pw, dumpAll, map);
-            pw.println(" ");
         }
 
         if (dumpAll) {
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 828eef7..5d60b9c 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -23,6 +23,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -31,7 +32,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.Slog;
 import android.util.TimeUtils;
 
@@ -260,6 +261,9 @@
                 IntentBindRecord b = it.next();
                 pw.print(prefix); pw.print("* IntentBindRecord{");
                         pw.print(Integer.toHexString(System.identityHashCode(b)));
+                        if ((b.collectFlags()&Context.BIND_AUTO_CREATE) != 0) {
+                            pw.append(" CREATE");
+                        }
                         pw.println("}:");
                 b.dumpInService(pw, prefix + "  ");
             }
@@ -296,7 +300,7 @@
         this.restarter = restarter;
         createTime = SystemClock.elapsedRealtime();
         lastActivity = SystemClock.uptimeMillis();
-        userId = UserId.getUserId(appInfo.uid);
+        userId = UserHandle.getUserId(appInfo.uid);
     }
 
     public AppBindRecord retrieveAppBindingLocked(Intent intent,
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 3a767c2..1bae9ca 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -19,7 +19,7 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.Slog;
 
 import java.io.PrintWriter;
@@ -101,7 +101,7 @@
         }
 
         if (info.applicationInfo != null) {
-            userId = UserId.getUserId(info.applicationInfo.uid);
+            userId = UserHandle.getUserId(info.applicationInfo.uid);
         }
     }
     
diff --git a/services/java/com/android/server/display/DisplayAdapter.java b/services/java/com/android/server/display/DisplayAdapter.java
index b623906..f9fa7a8 100644
--- a/services/java/com/android/server/display/DisplayAdapter.java
+++ b/services/java/com/android/server/display/DisplayAdapter.java
@@ -16,38 +16,33 @@
 
 package com.android.server.display;
 
-import android.view.Display;
-
 /**
- * A display adapter makes a single display devices available to the system.
+ * A display adapter makes zero or more display devices available to the system
+ * and provides facilities for discovering when displays are connected or disconnected.
  * <p>
  * For now, all display adapters are registered in the system server but
  * in principle it could be done from other processes.
  * </p>
  */
 public abstract class DisplayAdapter {
-    /** The current logical Display assignment for this adapter. Will change if other logical
-     * display is assigned to this adapter */
-    private int mDisplayId = Display.NO_DISPLAY;
-
-    /** Assign the displayId
-     * @hide */
-    public void setDisplayId(int displayId) {
-        mDisplayId = displayId;
-    }
-
-    /** Retrieve the displayId
-     * @hide */
-    public int getDisplayId() {
-        return mDisplayId;
-    }
-
     /**
-     * Gets the display adapter name.
+     * Gets the display adapter name for debugging purposes.
+     *
      * @return The display adapter name.
      */
     public abstract String getName();
 
-    // TODO: dynamically register display devices
-    public abstract DisplayDevice getDisplayDevice();
+    /**
+     * Registers the display adapter with the display manager.
+     * The display adapter should register any built-in display devices now.
+     * Other display devices can be registered dynamically later.
+     *
+     * @param listener The listener for callbacks.
+     */
+    public abstract void register(Listener listener);
+
+    public interface Listener {
+        public void onDisplayDeviceAdded(DisplayDevice device);
+        public void onDisplayDeviceRemoved(DisplayDevice device);
+    }
 }
diff --git a/services/java/com/android/server/display/DisplayDevice.java b/services/java/com/android/server/display/DisplayDevice.java
index 6d723f2..57002ff 100644
--- a/services/java/com/android/server/display/DisplayDevice.java
+++ b/services/java/com/android/server/display/DisplayDevice.java
@@ -18,8 +18,20 @@
 
 /**
  * Represents a physical display device such as the built-in display
- * or an external monitor.
+ * an external monitor, or a WiFi display.
  */
 public abstract class DisplayDevice {
+    /**
+     * Gets the display adapter that makes the display device available.
+     *
+     * @return The display adapter.
+     */
+    public abstract DisplayAdapter getAdapter();
+
+    /**
+     * Gets information about the display device.
+     *
+     * @param outInfo The object to populate with the information.
+     */
     public abstract void getInfo(DisplayDeviceInfo outInfo);
 }
diff --git a/services/java/com/android/server/display/DisplayDeviceInfo.java b/services/java/com/android/server/display/DisplayDeviceInfo.java
index c60c2e9..9c0f964 100644
--- a/services/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/java/com/android/server/display/DisplayDeviceInfo.java
@@ -21,6 +21,12 @@
  */
 public final class DisplayDeviceInfo {
     /**
+     * Gets the name of the display device, which may be derived from
+     * EDID or other sources.  The name may be displayed to the user.
+     */
+    public String name;
+
+    /**
      * The width of the display in its natural orientation, in pixels.
      * This value is not affected by display rotation.
      */
@@ -38,6 +44,7 @@
     public float yDpi;
 
     public void copyFrom(DisplayDeviceInfo other) {
+        name = other.name;
         width = other.width;
         height = other.height;
         refreshRate = other.refreshRate;
@@ -46,9 +53,10 @@
         yDpi = other.yDpi;
     }
 
+    // For debugging purposes
     @Override
     public String toString() {
-        return width + " x " + height + ", " + refreshRate + " fps, "
+        return "\"" + name + "\": " + width + " x " + height + ", " + refreshRate + " fps, "
                 + "density " + densityDpi + ", " + xDpi + " x " + yDpi + " dpi";
     }
 }
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 468bf21..2ebad1d 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -19,11 +19,10 @@
 import android.Manifest;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.hardware.display.DisplayManager;
 import android.hardware.display.IDisplayManager;
 import android.os.Binder;
 import android.os.SystemProperties;
-import android.util.Slog;
-import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface;
@@ -47,41 +46,27 @@
 
     private final Object mLock = new Object();
 
-    private Context mContext;
+    private final Context mContext;
     private final boolean mHeadless;
 
-    private int mDisplayIdSeq = Display.DEFAULT_DISPLAY;
-
-    /** All registered DisplayAdapters. */
     private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
+    private final DisplayInfo mDefaultDisplayInfo = new DisplayInfo();
 
-    /** All the DisplayAdapters showing the given displayId. */
-    private final SparseArray<ArrayList<DisplayAdapter>> mLogicalToPhysicals =
-            new SparseArray<ArrayList<DisplayAdapter>>();
-
-    /** All the DisplayInfos in the system indexed by deviceId */
-    private final SparseArray<DisplayInfo> mDisplayInfos = new SparseArray<DisplayInfo>();
-
-    private final ArrayList<DisplayCallback> mCallbacks =
-            new ArrayList<DisplayManagerService.DisplayCallback>();
-
-    public DisplayManagerService() {
+    public DisplayManagerService(Context context) {
+        mContext = context;
         mHeadless = SystemProperties.get(SYSTEM_HEADLESS).equals("1");
+
         registerDefaultDisplayAdapter();
     }
 
     private void registerDefaultDisplayAdapter() {
         if (mHeadless) {
-            registerDisplayAdapter(new HeadlessDisplayAdapter());
+            registerDisplayAdapter(new HeadlessDisplayAdapter(mContext));
         } else {
-            registerDisplayAdapter(new SurfaceFlingerDisplayAdapter());
+            registerDisplayAdapter(new SurfaceFlingerDisplayAdapter(mContext));
         }
     }
 
-    public void setContext(Context context) {
-        mContext = context;
-    }
-
     // FIXME: this isn't the right API for the long term
     public void getDefaultExternalDisplayDeviceInfo(DisplayDeviceInfo info) {
         // hardcoded assuming 720p touch screen plugged into HDMI and USB
@@ -90,6 +75,11 @@
         info.height = 720;
     }
 
+    /**
+     * Returns true if the device is headless.
+     *
+     * @return True if the device is headless.
+     */
     public boolean isHeadless() {
         return mHeadless;
     }
@@ -101,12 +91,10 @@
      */
     public void setDisplayInfo(int displayId, DisplayInfo info) {
         synchronized (mLock) {
-            DisplayInfo localInfo = mDisplayInfos.get(displayId);
-            if (localInfo == null) {
-                localInfo = new DisplayInfo();
-                mDisplayInfos.put(displayId, localInfo);
+            if (displayId != Display.DEFAULT_DISPLAY) {
+                throw new UnsupportedOperationException();
             }
-            localInfo.copyFrom(info);
+            mDefaultDisplayInfo.copyFrom(info);
         }
     }
 
@@ -118,177 +106,32 @@
     @Override // Binder call
     public boolean getDisplayInfo(int displayId, DisplayInfo outInfo) {
         synchronized (mLock) {
-            DisplayInfo localInfo = mDisplayInfos.get(displayId);
-            if (localInfo == null) {
+            if (displayId != Display.DEFAULT_DISPLAY) {
                 return false;
             }
-            outInfo.copyFrom(localInfo);
+            outInfo.copyFrom(mDefaultDisplayInfo);
             return true;
         }
     }
 
-    /**
-     * Inform the service of a new physical display. A new logical displayId is created and the new
-     * physical display is immediately bound to it. Use removeAdapterFromDisplay to disconnect it.
-     *
-     * @param adapter The wrapper for information associated with the physical display.
-     */
-    public void registerDisplayAdapter(DisplayAdapter adapter) {
-
-        int displayId;
-        DisplayCallback[] callbacks;
-
-        synchronized (mLock) {
-            displayId = mDisplayIdSeq;
-            do {
-                // Find the next unused displayId. (Pretend like it might ever wrap around).
-                mDisplayIdSeq++;
-                if (mDisplayIdSeq < 0) {
-                    mDisplayIdSeq = Display.DEFAULT_DISPLAY + 1;
-                }
-            } while (mDisplayInfos.get(mDisplayIdSeq) != null);
-
-            adapter.setDisplayId(displayId);
-
-            createDisplayInfoLocked(displayId, adapter);
-
-            ArrayList<DisplayAdapter> list = new ArrayList<DisplayAdapter>();
-            list.add(adapter);
-            mLogicalToPhysicals.put(displayId, list);
-
-            mDisplayAdapters.add(adapter);
-            callbacks = mCallbacks.toArray(new DisplayCallback[mCallbacks.size()]);
-        }
-
-        for (int i = callbacks.length - 1; i >= 0; i--) {
-            callbacks[i].displayAdded(displayId);
-        }
-
-        // TODO: Notify SurfaceFlinger of new addition.
-    }
-
-    /**
-     * Connect a logical display to a physical display. Will remove the physical display from any
-     * logical display it is currently attached to.
-     *
-     * @param displayId The logical display. Will be created if it does not already exist.
-     * @param adapter The physical display.
-     */
-    public void addAdapterToDisplay(int displayId, DisplayAdapter adapter) {
-        if (adapter == null) {
-            // TODO: Or throw NPE?
-            Slog.e(TAG, "addDeviceToDisplay: Attempt to add null adapter");
-            return;
-        }
-
-        synchronized (mLock) {
-            if (!mDisplayAdapters.contains(adapter)) {
-                // TOOD: Handle unregistered adapter with exception or return value.
-                Slog.e(TAG, "addDeviceToDisplay: Attempt to add an unregistered adapter");
-                return;
+    private void registerDisplayAdapter(DisplayAdapter adapter) {
+        mDisplayAdapters.add(adapter);
+        adapter.register(new DisplayAdapter.Listener() {
+            @Override
+            public void onDisplayDeviceAdded(DisplayDevice device) {
+                DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
+                device.getInfo(deviceInfo);
+                copyDisplayInfoFromDeviceInfo(mDefaultDisplayInfo, deviceInfo);
             }
 
-            DisplayInfo displayInfo = mDisplayInfos.get(displayId);
-            if (displayInfo == null) {
-                createDisplayInfoLocked(displayId, adapter);
+            @Override
+            public void onDisplayDeviceRemoved(DisplayDevice device) {
             }
-
-            Integer oldDisplayId = adapter.getDisplayId();
-            if (oldDisplayId != Display.NO_DISPLAY) {
-                if (oldDisplayId == displayId) {
-                    // adapter already added to displayId.
-                    return;
-                }
-
-                removeAdapterLocked(adapter);
-            }
-
-            ArrayList<DisplayAdapter> list = mLogicalToPhysicals.get(displayId);
-            if (list == null) {
-                list = new ArrayList<DisplayAdapter>();
-                mLogicalToPhysicals.put(displayId, list);
-            }
-            list.add(adapter);
-            adapter.setDisplayId(displayId);
-        }
-
-        // TODO: Notify SurfaceFlinger of new addition.
+        });
     }
 
-    /**
-     * Disconnect the physical display from whichever logical display it is attached to.
-     * @param adapter The physical display to detach.
-     */
-    public void removeAdapterFromDisplay(DisplayAdapter adapter) {
-        if (adapter == null) {
-            // TODO: Or throw NPE?
-            return;
-        }
-
-        synchronized (mLock) {
-            if (!mDisplayAdapters.contains(adapter)) {
-                // TOOD: Handle unregistered adapter with exception or return value.
-                Slog.e(TAG, "removeDeviceFromDisplay: Attempt to remove an unregistered adapter");
-                return;
-            }
-
-            removeAdapterLocked(adapter);
-        }
-
-        // TODO: Notify SurfaceFlinger of removal.
-    }
-
-    public void registerDisplayCallback(final DisplayCallback callback) {
-        synchronized (mLock) {
-            if (!mCallbacks.contains(callback)) {
-                mCallbacks.add(callback);
-            }
-        }
-    }
-
-    public void unregisterDisplayCallback(final DisplayCallback callback) {
-        synchronized (mLock) {
-            mCallbacks.remove(callback);
-        }
-    }
-
-    /**
-     * Create a new logical DisplayInfo and fill it in with information from the physical display.
-     * @param displayId The logical identifier.
-     * @param adapter The physical display for initial values.
-     */
-    private void createDisplayInfoLocked(int displayId, DisplayAdapter adapter) {
-        DisplayInfo displayInfo = new DisplayInfo();
-        DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
-        adapter.getDisplayDevice().getInfo(deviceInfo);
-        copyDisplayInfoFromDeviceInfo(displayInfo, deviceInfo);
-        mDisplayInfos.put(displayId, displayInfo);
-    }
-
-    /**
-     * Disconnect a physical display from its logical display. If there are no more physical
-     * displays attached to the logical display, delete the logical display.
-     * @param adapter The physical display to detach.
-     */
-    void removeAdapterLocked(DisplayAdapter adapter) {
-        int displayId = adapter.getDisplayId();
-        adapter.setDisplayId(Display.NO_DISPLAY);
-
-        ArrayList<DisplayAdapter> list = mLogicalToPhysicals.get(displayId);
-        if (list != null) {
-            list.remove(adapter);
-            if (list.isEmpty()) {
-                mLogicalToPhysicals.remove(displayId);
-                // TODO: Keep count of Windows attached to logical display and don't delete if
-                // there are any outstanding. Also, what keeps the WindowManager from continuing
-                // to use the logical display?
-                mDisplayInfos.remove(displayId);
-            }
-        }
-    }
-
-    private void copyDisplayInfoFromDeviceInfo(DisplayInfo displayInfo,
-                                               DisplayDeviceInfo deviceInfo) {
+    private void copyDisplayInfoFromDeviceInfo(
+            DisplayInfo displayInfo, DisplayDeviceInfo deviceInfo) {
         // Bootstrap the logical display using the physical display.
         displayInfo.appWidth = deviceInfo.width;
         displayInfo.appHeight = deviceInfo.height;
@@ -319,19 +162,15 @@
 
         pw.println("Headless: " + mHeadless);
 
-        DisplayDeviceInfo info = new DisplayDeviceInfo();
-        for (DisplayAdapter adapter : mDisplayAdapters) {
-            pw.println("Display for adapter " + adapter.getName()
-                + " assigned to Display " + adapter.getDisplayId());
-            DisplayDevice device = adapter.getDisplayDevice();
-            pw.print("  ");
-            device.getInfo(info);
-            pw.println(info);
-        }
-    }
+        synchronized (mLock) {
+            for (DisplayAdapter adapter : mDisplayAdapters) {
+                pw.println("Adapter: " + adapter.getName());
+            }
 
-    public interface DisplayCallback {
-        public void displayAdded(int displayId);
-        public void displayRemoved(int displayId);
+            pw.println("Default display info: " + mDefaultDisplayInfo);
+        }
+
+        pw.println("Default display: "
+                + DisplayManager.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY));
     }
 }
diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
index 3eaf40f..17c2360 100644
--- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java
+++ b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
@@ -16,23 +16,20 @@
 
 package com.android.server.display;
 
+import android.content.Context;
 import android.util.DisplayMetrics;
 
 /**
  * Provides a fake default display for headless systems.
  */
 public final class HeadlessDisplayAdapter extends DisplayAdapter {
-    private final DisplayDevice mDefaultDisplay = new DisplayDevice() {
-        @Override
-        public void getInfo(DisplayDeviceInfo outInfo) {
-            outInfo.width = 640;
-            outInfo.height = 480;
-            outInfo.refreshRate = 60;
-            outInfo.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
-            outInfo.xDpi = 160;
-            outInfo.yDpi = 160;
-        }
-    };
+    private final Context mContext;
+    private final HeadlessDisplayDevice mDefaultDisplayDevice;
+
+    public HeadlessDisplayAdapter(Context context) {
+        mContext = context;
+        mDefaultDisplayDevice = new HeadlessDisplayDevice();
+    }
 
     @Override
     public String getName() {
@@ -40,7 +37,26 @@
     }
 
     @Override
-    public DisplayDevice getDisplayDevice() {
-        return mDefaultDisplay;
+    public void register(Listener listener) {
+        listener.onDisplayDeviceAdded(mDefaultDisplayDevice);
+    }
+
+    private final class HeadlessDisplayDevice extends DisplayDevice {
+        @Override
+        public DisplayAdapter getAdapter() {
+            return HeadlessDisplayAdapter.this;
+        }
+
+        @Override
+        public void getInfo(DisplayDeviceInfo outInfo) {
+            outInfo.name = mContext.getResources().getString(
+                    com.android.internal.R.string.display_manager_built_in_display);
+            outInfo.width = 640;
+            outInfo.height = 480;
+            outInfo.refreshRate = 60;
+            outInfo.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
+            outInfo.xDpi = 160;
+            outInfo.yDpi = 160;
+        }
     }
 }
diff --git a/services/java/com/android/server/display/SurfaceFlingerDisplayAdapter.java b/services/java/com/android/server/display/SurfaceFlingerDisplayAdapter.java
index 539f7c1..9531acb 100644
--- a/services/java/com/android/server/display/SurfaceFlingerDisplayAdapter.java
+++ b/services/java/com/android/server/display/SurfaceFlingerDisplayAdapter.java
@@ -16,18 +16,21 @@
 
 package com.android.server.display;
 
+import android.content.Context;
+
 /**
  * A display adapter for the displays managed by Surface Flinger.
  */
 public final class SurfaceFlingerDisplayAdapter extends DisplayAdapter {
+    private final Context mContext;
+    private final SurfaceFlingerDisplayDevice mDefaultDisplayDevice;
+
     private static native void nativeGetDefaultDisplayDeviceInfo(DisplayDeviceInfo outInfo);
 
-    private final DisplayDevice mDefaultDisplay = new DisplayDevice() {
-        @Override
-        public void getInfo(DisplayDeviceInfo outInfo) {
-            nativeGetDefaultDisplayDeviceInfo(outInfo);
-        }
-    };
+    public SurfaceFlingerDisplayAdapter(Context context) {
+        mContext = context;
+        mDefaultDisplayDevice = new SurfaceFlingerDisplayDevice();
+    }
 
     @Override
     public String getName() {
@@ -35,7 +38,21 @@
     }
 
     @Override
-    public DisplayDevice getDisplayDevice() {
-        return mDefaultDisplay;
+    public void register(Listener listener) {
+        listener.onDisplayDeviceAdded(mDefaultDisplayDevice);
+    }
+
+    private final class SurfaceFlingerDisplayDevice extends DisplayDevice {
+        @Override
+        public DisplayAdapter getAdapter() {
+            return SurfaceFlingerDisplayAdapter.this;
+        }
+
+        @Override
+        public void getInfo(DisplayDeviceInfo outInfo) {
+            outInfo.name = mContext.getResources().getString(
+                    com.android.internal.R.string.display_manager_built_in_display);
+            nativeGetDefaultDisplayDeviceInfo(outInfo);
+        }
     }
 }
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index 21100e2..0b8ff62 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -1218,8 +1218,12 @@
     }
 
     // Native callback.
-    private void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
-        mCallbacks.notifyLidSwitchChanged(whenNanos, lidOpen);
+    private void notifySwitch(long whenNanos, int switchCode, int switchValue) {
+        switch (switchCode) {
+            case SW_LID:
+                mCallbacks.notifyLidSwitchChanged(whenNanos, switchValue == 0);
+                break;
+        }
     }
 
     // Native callback.
diff --git a/services/java/com/android/server/location/GeofenceManager.java b/services/java/com/android/server/location/GeofenceManager.java
index 338cd5d..26d9c15 100644
--- a/services/java/com/android/server/location/GeofenceManager.java
+++ b/services/java/com/android/server/location/GeofenceManager.java
@@ -34,9 +34,13 @@
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.server.LocationManagerService;
 
 public class GeofenceManager implements LocationListener, PendingIntent.OnFinished {
     private static final String TAG = "GeofenceManager";
+    private static final boolean D = LocationManagerService.D;
 
     /**
      * Assume a maximum land speed, as a heuristic to throttle location updates.
@@ -49,6 +53,7 @@
     private final LocationManager mLocationManager;
     private final PowerManager.WakeLock mWakeLock;
     private final Looper mLooper;  // looper thread to take location updates on
+    private final LocationBlacklist mBlacklist;
 
     private Object mLock = new Object();
 
@@ -56,12 +61,13 @@
     private Location mLastLocation;
     private List<GeofenceState> mFences = new LinkedList<GeofenceState>();
 
-    public GeofenceManager(Context context) {
+    public GeofenceManager(Context context, LocationBlacklist blacklist) {
         mContext = context;
         mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
         PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
         mLooper = Looper.myLooper();
+        mBlacklist = blacklist;
 
         LocationRequest request = new LocationRequest()
                 .setQuality(LocationRequest.POWER_NONE)
@@ -145,6 +151,12 @@
             removeExpiredFencesLocked();
 
             for (GeofenceState state : mFences) {
+                if (mBlacklist.isBlacklisted(state.mPackageName)) {
+                    if (D) Log.d(TAG, "skipping geofence processing for blacklisted app: " +
+                            state.mPackageName);
+                    continue;
+                }
+
                 int event = state.processLocation(location);
                 if ((event & GeofenceState.FLAG_ENTER) != 0) {
                     enterIntents.add(state.mIntent);
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 3cd767d..2d4fa2b 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -496,6 +496,7 @@
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(ALARM_WAKEUP);
         intentFilter.addAction(ALARM_TIMEOUT);
+        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         mContext.registerReceiver(mBroadcastReciever, intentFilter);
     }
 
@@ -845,6 +846,9 @@
                 }
             }
         }
+
+        // save current uids
+        mClientUids = uids;
     }
 
     @Override
diff --git a/services/java/com/android/server/location/LocationBlacklist.java b/services/java/com/android/server/location/LocationBlacklist.java
new file mode 100644
index 0000000..71fa9f9
--- /dev/null
+++ b/services/java/com/android/server/location/LocationBlacklist.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.server.location;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.server.LocationManagerService;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Allows applications to be blacklisted from location updates at run-time.
+ *
+ * This is a silent blacklist. Applications can still call Location Manager
+ * API's, but they just won't receive any locations.
+ */
+public final class LocationBlacklist extends ContentObserver {
+    private static final String TAG = "LocationBlacklist";
+    private static final boolean D = LocationManagerService.D;
+    private static final String BLACKLIST_CONFIG_NAME = "locationPackagePrefixBlacklist";
+    private static final String WHITELIST_CONFIG_NAME = "locationPackagePrefixWhitelist";
+
+    private final Context mContext;
+    private final Object mLock = new Object();
+
+    // all fields below synchronized on mLock
+    private String[] mWhitelist = new String[0];
+    private String[] mBlacklist = new String[0];
+    
+    public LocationBlacklist(Context context, Handler handler) {
+        super(handler);
+        mContext = context;
+    }
+
+    public void init() {
+        mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
+                BLACKLIST_CONFIG_NAME), false, this);
+//        mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
+//                WHITELIST_CONFIG_NAME), false, this);
+        reloadBlacklist();
+    }
+
+    private void reloadBlacklist() {
+        String blacklist[] = getStringArray(BLACKLIST_CONFIG_NAME);
+        String whitelist[] = getStringArray(WHITELIST_CONFIG_NAME);
+        synchronized (mLock) {
+            mWhitelist = whitelist;
+            Slog.i(TAG, "whitelist: " + Arrays.toString(mWhitelist));
+            mBlacklist = blacklist;
+            Slog.i(TAG, "blacklist: " + Arrays.toString(mBlacklist));
+        }
+    }
+
+    /**
+     * Return true if in blacklist
+     * (package name matches blacklist, and does not match whitelist)
+     */
+    public boolean isBlacklisted(String packageName) {
+        synchronized (mLock) {
+            for (String black : mBlacklist) {
+                if (packageName.startsWith(black)) {
+                    if (inWhitelist(packageName)) {
+                        continue;
+                    } else {
+                        if (D) Log.d(TAG, "dropping location (blacklisted): "
+                                + packageName + " matches " + black);
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Return true if any of packages are in whitelist
+     */
+    private boolean inWhitelist(String pkg) {
+        synchronized (mLock) {
+            for (String white : mWhitelist) {
+                if (pkg.startsWith(white)) return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void onChange(boolean selfChange) {
+        reloadBlacklist();
+    }
+
+    private String[] getStringArray(String key) {
+        String flatString = Settings.Secure.getString(mContext.getContentResolver(), key);
+        if (flatString == null) {
+            return new String[0];
+        }
+        String[] splitStrings = flatString.split(",");
+        ArrayList<String> result = new ArrayList<String>();
+        for (String pkg : splitStrings) {
+            pkg = pkg.trim();
+            if (pkg.isEmpty()) {
+                continue;
+            }
+            result.add(pkg);
+        }
+        return result.toArray(new String[result.size()]);
+    }
+
+    public void dump(PrintWriter pw) {
+        pw.println("mWhitelist=" + Arrays.toString(mWhitelist) + " mBlacklist=" +
+                Arrays.toString(mBlacklist));
+    }
+}
diff --git a/services/java/com/android/server/location/LocationFudger.java b/services/java/com/android/server/location/LocationFudger.java
new file mode 100644
index 0000000..57bc1c5
--- /dev/null
+++ b/services/java/com/android/server/location/LocationFudger.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.security.SecureRandom;
+import android.location.Location;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.util.Log;
+
+
+/**
+ * Contains the logic to obfuscate (fudge) locations for coarse applications.
+ *
+ * <p>The goal is just to prevent applications with only
+ * the coarse location permission from receiving a fine location.
+ */
+public class LocationFudger {
+    private static final boolean D = false;
+    private static final String TAG = "LocationFudge";
+
+    private static final String EXTRA_COARSE_LOCATION = "coarseLocation";
+
+    /**
+     * This is the main control: Best location accuracy allowed for coarse applications.
+     */
+    private static final float ACCURACY_METERS = 200.0f;
+
+    /**
+     * The distance between grids for snap-to-grid. See {@link #createCoarse}.
+     */
+    private static final double GRID_SIZE_METERS = ACCURACY_METERS;
+
+    /**
+     * Standard deviation of the (normally distributed) random offset applied
+     * to coarse locations. It does not need to be as large as
+     * {@link #COARSE_ACCURACY_METERS} because snap-to-grid is the primary obfuscation
+     * method. See further details in the implementation.
+     */
+    private static final double STANDARD_DEVIATION_METERS = GRID_SIZE_METERS / 4.0;
+
+    /**
+     * This is the fastest interval that applications can receive coarse
+     * locations.
+     */
+    public static final long FASTEST_INTERVAL_MS = 10 * 60 * 1000;  // 10 minutes
+
+    /**
+     * The duration until we change the random offset.
+     */
+    private static final long CHANGE_INTERVAL_MS = 60 * 60 * 1000;  // 1 hour
+
+    /**
+     * The percentage that we change the random offset at every interval.
+     *
+     * <p>0.0 indicates the random offset doesn't change. 1.0
+     * indicates the random offset is completely replaced every interval.
+     */
+    private static final double CHANGE_PER_INTERVAL = 0.03;  // 3% change
+
+    // Pre-calculated weights used to move the random offset.
+    //
+    // The goal is to iterate on the previous offset, but keep
+    // the resulting standard deviation the same. The variance of
+    // two gaussian distributions summed together is equal to the
+    // sum of the variance of each distribution. So some quick
+    // algebra results in the following sqrt calculation to
+    // weigh in a new offset while keeping the final standard
+    // deviation unchanged.
+    private static final double NEW_WEIGHT = CHANGE_PER_INTERVAL;
+    private static final double PREVIOUS_WEIGHT = Math.sqrt(1 - NEW_WEIGHT * NEW_WEIGHT);
+
+    /**
+     * This number actually varies because the earth is not round, but
+     * 111,000 meters is considered generally acceptable.
+     */
+    private static final int APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR = 111000;
+
+    /**
+     * Maximum latitude.
+     *
+     * <p>We pick a value 1 meter away from 90.0 degrees in order
+     * to keep cosine(MAX_LATITUDE) to a non-zero value, so that we avoid
+     * divide by zero fails.
+     */
+    private static final double MAX_LATITUDE = 90.0 -
+            (1.0 / APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR);
+
+    private final Object mLock = new Object();
+    private final SecureRandom mRandom = new SecureRandom();
+
+    // all fields below protected by mLock
+    private double mOffsetLatitudeMeters;
+    private double mOffsetLongitudeMeters;
+    private long mNextInterval;
+
+    public LocationFudger() {
+        mOffsetLatitudeMeters = nextOffset();
+        mOffsetLongitudeMeters = nextOffset();
+        mNextInterval = SystemClock.elapsedRealtime() + CHANGE_INTERVAL_MS;
+    }
+
+    /**
+     * Get the cached coarse location, or generate a new one and cache it.
+     */
+    public Location getOrCreate(Location location) {
+        Bundle extras = location.getExtras();
+        if (extras == null) {
+            return addCoarseLocationExtra(location);
+        }
+        Parcelable parcel = extras.getParcelable(EXTRA_COARSE_LOCATION);
+        if (parcel == null) {
+            return addCoarseLocationExtra(location);
+        }
+        if (!(parcel instanceof Location)) {
+            return addCoarseLocationExtra(location);
+        }
+        Location coarse = (Location) parcel;
+        if (coarse.getAccuracy() < ACCURACY_METERS) {
+            return addCoarseLocationExtra(location);
+        }
+        return coarse;
+    }
+
+    private Location addCoarseLocationExtra(Location location) {
+        Bundle extras = location.getExtras();
+        if (extras == null) extras = new Bundle();
+        Location coarse = createCoarse(location);
+        extras.putParcelable(EXTRA_COARSE_LOCATION, coarse);
+        location.setExtras(extras);
+        return coarse;
+    }
+
+    /**
+     * Create a coarse location.
+     *
+     * <p>Two techniques are used: random offsets and snap-to-grid.
+     *
+     * <p>First we add a random offset. This mitigates against detecting
+     * grid transitions. Without a random offset it is possible to detect
+     * a users position very accurately when they cross a grid boundary.
+     * The random offset changes very slowly over time, to mitigate against
+     * taking many location samples and averaging them out.
+     *
+     * <p>Second we snap-to-grid (quantize). This has the nice property of
+     * producing stable results, and mitigating against taking many samples
+     * to average out a random offset.
+     */
+    private Location createCoarse(Location fine) {
+        Location coarse = new Location(fine);
+
+        // clean all the optional information off the location, because
+        // this can leak detailed location information
+        coarse.removeBearing();
+        coarse.removeSpeed();
+        coarse.removeAltitude();
+        coarse.setExtras(null);
+
+        double lat = coarse.getLatitude();
+        double lon = coarse.getLongitude();
+
+        // wrap
+        lat = wrapLatitude(lat);
+        lon = wrapLongitude(lon);
+
+        // Step 1) apply a random offset
+        //
+        // The goal of the random offset is to prevent the application
+        // from determining that the device is on a grid boundary
+        // when it crosses from one grid to the next.
+        //
+        // We apply the offset even if the location already claims to be
+        // inaccurate, because it may be more accurate than claimed.
+        synchronized (mLock) {
+            updateRandomOffsetLocked();
+            // perform lon first whilst lat is still within bounds
+            lon += metersToDegreesLongitude(mOffsetLongitudeMeters, lat);
+            lat += metersToDegreesLatitude(mOffsetLatitudeMeters);
+            if (D) Log.d(TAG, String.format("applied offset of %.0f, %.0f (meters)",
+                    mOffsetLongitudeMeters, mOffsetLatitudeMeters));
+        }
+
+        // wrap
+        lat = wrapLatitude(lat);
+        lon = wrapLongitude(lon);
+
+        // Step 2) Snap-to-grid (quantize)
+        //
+        // This is the primary means of obfuscation. It gives nice consistent
+        // results and is very effective at hiding the true location
+        // (as long as you are not sitting on a grid boundary, which
+        // step 1 mitigates).
+        //
+        // Note we quantize the latitude first, since the longitude
+        // quantization depends on the latitude value and so leaks information
+        // about the latitude
+        double latGranularity = metersToDegreesLatitude(GRID_SIZE_METERS);
+        lat = Math.round(lat / latGranularity) * latGranularity;
+        double lonGranularity = metersToDegreesLongitude(GRID_SIZE_METERS, lat);
+        lon = Math.round(lon / lonGranularity) * lonGranularity;
+
+        // wrap again
+        lat = wrapLatitude(lat);
+        lon = wrapLongitude(lon);
+
+        // apply
+        coarse.setLatitude(lat);
+        coarse.setLongitude(lon);
+        coarse.setAccuracy(Math.max(ACCURACY_METERS, coarse.getAccuracy()));
+
+        if (D) Log.d(TAG, "fudged " + fine + " to " + coarse);
+        return coarse;
+    }
+
+    /**
+     * Update the random offset over time.
+     *
+     * <p>If the random offset was new for every location
+     * fix then an application can more easily average location results
+     * over time,
+     * especially when the location is near a grid boundary. On the
+     * other hand if the random offset is constant then if an application
+     * found a way to reverse engineer the offset they would be able
+     * to detect location at grid boundaries very accurately. So
+     * we choose a random offset and then very slowly move it, to
+     * make both approaches very hard.
+     *
+     * <p>The random offset does not need to be large, because snap-to-grid
+     * is the primary obfuscation mechanism. It just needs to be large
+     * enough to stop information leakage as we cross grid boundaries.
+     */
+    private void updateRandomOffsetLocked() {
+        long now = SystemClock.elapsedRealtime();
+        if (now < mNextInterval) {
+            return;
+        }
+
+        if (D) Log.d(TAG, String.format("old offset: %.0f, %.0f (meters)",
+                mOffsetLongitudeMeters, mOffsetLatitudeMeters));
+
+        // ok, need to update the random offset
+        mNextInterval = now + CHANGE_INTERVAL_MS;
+
+        mOffsetLatitudeMeters *= PREVIOUS_WEIGHT;
+        mOffsetLatitudeMeters += NEW_WEIGHT * nextOffset();
+        mOffsetLongitudeMeters *= PREVIOUS_WEIGHT;
+        mOffsetLongitudeMeters += NEW_WEIGHT * nextOffset();
+
+        if (D) Log.d(TAG, String.format("new offset: %.0f, %.0f (meters)",
+                mOffsetLongitudeMeters, mOffsetLatitudeMeters));
+    }
+
+    private double nextOffset() {
+        return mRandom.nextGaussian() * STANDARD_DEVIATION_METERS;
+    }
+
+    private static double wrapLatitude(double lat) {
+         if (lat > MAX_LATITUDE) {
+             lat = MAX_LATITUDE;
+         }
+         if (lat < -MAX_LATITUDE) {
+             lat = -MAX_LATITUDE;
+         }
+         return lat;
+    }
+
+    private static double wrapLongitude(double lon) {
+        lon %= 360.0;  // wraps into range (-360.0, +360.0)
+        if (lon >= 180.0) {
+            lon -= 360.0;
+        }
+        if (lon < -180.0) {
+            lon += 360.0;
+        }
+        return lon;
+    }
+
+    private static double metersToDegreesLatitude(double distance) {
+        return distance / APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR;
+    }
+
+    /**
+     * Requires latitude since longitudinal distances change with distance from equator.
+     */
+    private static double metersToDegreesLongitude(double distance, double lat) {
+        return distance / APPROXIMATE_METERS_PER_DEGREE_AT_EQUATOR / Math.cos(Math.toRadians(lat));
+    }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println(String.format("offset: %.0f, %.0f (meters)", mOffsetLongitudeMeters,
+                mOffsetLatitudeMeters));
+    }
+}
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 46c24b0..a7cba5a 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -112,7 +112,7 @@
 import android.os.MessageQueue.IdleHandler;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
@@ -426,7 +426,7 @@
 
             final String action = intent.getAction();
             final int uid = intent.getIntExtra(EXTRA_UID, 0);
-            final int appId = UserId.getAppId(uid);
+            final int appId = UserHandle.getAppId(uid);
             synchronized (mRulesLock) {
                 if (ACTION_PACKAGE_ADDED.equals(action)) {
                     // NOTE: PACKAGE_ADDED is currently only sent once, and is
@@ -1188,8 +1188,8 @@
                         final int uid = readIntAttribute(in, ATTR_UID);
                         final int policy = readIntAttribute(in, ATTR_POLICY);
 
-                        final int appId = UserId.getAppId(uid);
-                        if (UserId.isApp(appId)) {
+                        final int appId = UserHandle.getAppId(uid);
+                        if (UserHandle.isApp(appId)) {
                             setAppPolicyUnchecked(appId, policy, false);
                         } else {
                             Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring");
@@ -1198,7 +1198,7 @@
                         final int appId = readIntAttribute(in, ATTR_APP_ID);
                         final int policy = readIntAttribute(in, ATTR_POLICY);
 
-                        if (UserId.isApp(appId)) {
+                        if (UserHandle.isApp(appId)) {
                             setAppPolicyUnchecked(appId, policy, false);
                         } else {
                             Slog.w(TAG, "unable to apply policy to appId " + appId + "; ignoring");
@@ -1304,7 +1304,7 @@
     public void setAppPolicy(int appId, int policy) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
 
-        if (!UserId.isApp(appId)) {
+        if (!UserHandle.isApp(appId)) {
             throw new IllegalArgumentException("cannot apply policy to appId " + appId);
         }
 
@@ -1698,7 +1698,7 @@
         final PackageManager pm = mContext.getPackageManager();
         final List<ApplicationInfo> apps = pm.getInstalledApplications(0);
         for (ApplicationInfo app : apps) {
-            final int appId = UserId.getAppId(app.uid);
+            final int appId = UserHandle.getAppId(app.uid);
             updateRulesForAppLocked(appId);
         }
 
@@ -1710,7 +1710,7 @@
     private void updateRulesForAppLocked(int appId) {
         UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         for (UserInfo user : um.getUsers()) {
-            final int uid = UserId.getUid(user.id, appId);
+            final int uid = UserHandle.getUid(user.id, appId);
             updateRulesForUidLocked(uid);
         }
     }
@@ -1718,7 +1718,7 @@
     private static boolean isUidValidForRules(int uid) {
         // allow rules on specific system services, and any apps
         if (uid == android.os.Process.MEDIA_UID || uid == android.os.Process.DRM_UID
-                || UserId.isApp(uid)) {
+                || UserHandle.isApp(uid)) {
             return true;
         }
 
@@ -1728,7 +1728,7 @@
     private void updateRulesForUidLocked(int uid) {
         if (!isUidValidForRules(uid)) return;
 
-        final int appId = UserId.getAppId(uid);
+        final int appId = UserHandle.getAppId(uid);
         final int appPolicy = getAppPolicy(appId);
         final boolean uidForeground = isUidForeground(uid);
 
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java
index 48004bb..d4fe3fb 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -338,12 +338,14 @@
         return execute(builder.toString());
     }
 
-    public int getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath,
+    public int getSizeInfo(String pkgName, int persona, String apkPath, String fwdLockApkPath,
             String asecPath, PackageStats pStats) {
         StringBuilder builder = new StringBuilder("getsize");
         builder.append(' ');
         builder.append(pkgName);
         builder.append(' ');
+        builder.append(persona);
+        builder.append(' ');
         builder.append(apkPath);
         builder.append(' ');
         builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index f257203..a76f854 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -79,6 +79,7 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.Signature;
 import android.content.pm.ManifestDigest;
+import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VerifierInfo;
 import android.net.Uri;
@@ -97,10 +98,11 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SELinux;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings.Secure;
 import android.security.SystemKeyStore;
@@ -145,6 +147,7 @@
 import libcore.io.ErrnoException;
 import libcore.io.IoUtils;
 import libcore.io.Libcore;
+import libcore.io.StructStat;
 
 /**
  * Keep track of all those .apks everywhere.
@@ -304,8 +307,6 @@
     File mScanningPath;
     int mLastScanError;
 
-    final int[] mOutPermissions = new int[3];
-
     // ----------------------------------------------------------------
 
     // Keys are String (package name), values are Package.  This also serves
@@ -691,15 +692,15 @@
                             }
                             sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
                                     res.pkg.applicationInfo.packageName,
-                                    extras, null, null, UserId.USER_ALL);
+                                    extras, null, null, UserHandle.USER_ALL);
                             if (update) {
                                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
                                         res.pkg.applicationInfo.packageName,
-                                        extras, null, null, UserId.USER_ALL);
+                                        extras, null, null, UserHandle.USER_ALL);
                                 sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                                         null, null,
                                         res.pkg.applicationInfo.packageName, null,
-                                        UserId.USER_ALL);
+                                        UserHandle.USER_ALL);
                             }
                             if (res.removedInfo.args != null) {
                                 // Remove the replaced package's older resources safely now
@@ -1630,14 +1631,14 @@
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
             if(p != null) {
-                return UserId.getUid(userId, p.applicationInfo.uid);
+                return UserHandle.getUid(userId, p.applicationInfo.uid);
             }
             PackageSetting ps = mSettings.mPackages.get(packageName);
             if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) {
                 return -1;
             }
             p = ps.pkg;
-            return p != null ? UserId.getUid(userId, p.applicationInfo.uid) : -1;
+            return p != null ? UserHandle.getUid(userId, p.applicationInfo.uid) : -1;
         }
     }
 
@@ -1961,7 +1962,7 @@
     }
 
     private void checkValidCaller(int uid, int userId) {
-        if (UserId.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0)
+        if (UserHandle.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0)
             return;
 
         throw new SecurityException("Caller uid=" + uid
@@ -1990,7 +1991,7 @@
 
     public int checkUidPermission(String permName, int uid) {
         synchronized (mPackages) {
-            Object obj = mSettings.getUserIdLPr(UserId.getAppId(uid));
+            Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
             if (obj != null) {
                 GrantedPermissions gp = (GrantedPermissions)obj;
                 if (gp.grantedPermissions.contains(permName)) {
@@ -2024,7 +2025,7 @@
         if (permName != null) {
             BasePermission bp = findPermissionTreeLP(permName);
             if (bp != null) {
-                if (bp.uid == UserId.getAppId(Binder.getCallingUid())) {
+                if (bp.uid == UserHandle.getAppId(Binder.getCallingUid())) {
                     return bp;
                 }
                 throw new SecurityException("Calling uid "
@@ -2227,8 +2228,8 @@
 
     public int checkUidSignatures(int uid1, int uid2) {
         // Map to base uids.
-        uid1 = UserId.getAppId(uid1);
-        uid2 = UserId.getAppId(uid2);
+        uid1 = UserHandle.getAppId(uid1);
+        uid2 = UserHandle.getAppId(uid2);
         // reader
         synchronized (mPackages) {
             Signature[] s1;
@@ -2286,7 +2287,7 @@
     }
 
     public String[] getPackagesForUid(int uid) {
-        uid = UserId.getAppId(uid);
+        uid = UserHandle.getAppId(uid);
         // reader
         synchronized (mPackages) {
             Object obj = mSettings.getUserIdLPr(uid);
@@ -2311,7 +2312,7 @@
     public String getNameForUid(int uid) {
         // reader
         synchronized (mPackages) {
-            Object obj = mSettings.getUserIdLPr(UserId.getAppId(uid));
+            Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
             if (obj instanceof SharedUserSetting) {
                 final SharedUserSetting sus = (SharedUserSetting) obj;
                 return sus.name + ":" + sus.userId;
@@ -2422,6 +2423,9 @@
                 final int M = prefs.size();
                 for (int i=0; i<M; i++) {
                     final PreferredActivity pa = prefs.get(i);
+                    if (pa.mUserId != userId) {
+                        continue;
+                    }
                     if (pa.mPref.mMatch != match) {
                         continue;
                     }
@@ -2791,7 +2795,7 @@
         final ParceledListSlice<PackageInfo> list = new ParceledListSlice<PackageInfo>();
         final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
         final String[] keys;
-        int userId = UserId.getCallingUserId();
+        int userId = UserHandle.getCallingUserId();
 
         // writer
         synchronized (mPackages) {
@@ -2890,7 +2894,7 @@
         // reader
         synchronized (mPackages) {
             final Iterator<PackageParser.Package> i = mPackages.values().iterator();
-            final int userId = UserId.getCallingUserId();
+            final int userId = UserHandle.getCallingUserId();
             while (i.hasNext()) {
                 final PackageParser.Package p = i.next();
                 if (p.applicationInfo != null
@@ -2938,7 +2942,7 @@
         synchronized (mPackages) {
             final Iterator<Map.Entry<String, PackageParser.Provider>> i = mProviders.entrySet()
                     .iterator();
-            final int userId = UserId.getCallingUserId();
+            final int userId = UserHandle.getCallingUserId();
             while (i.hasNext()) {
                 Map.Entry<String, PackageParser.Provider> entry = i.next();
                 PackageParser.Provider p = entry.getValue();
@@ -2965,14 +2969,14 @@
         synchronized (mPackages) {
             final Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator();
             final int userId = processName != null ?
-                    UserId.getUserId(uid) : UserId.getCallingUserId();
+                    UserHandle.getUserId(uid) : UserHandle.getCallingUserId();
             while (i.hasNext()) {
                 final PackageParser.Provider p = i.next();
                 PackageSetting ps = mSettings.mPackages.get(p.owner.packageName);
                 if (p.info.authority != null
                         && (processName == null
                                 || (p.info.processName.equals(processName)
-                                        && UserId.isSameApp(p.info.applicationInfo.uid, uid)))
+                                        && UserHandle.isSameApp(p.info.applicationInfo.uid, uid)))
                         && mSettings.isEnabledLPr(p.info, flags, userId)
                         && (!mSafeMode
                                 || (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
@@ -3789,14 +3793,18 @@
             boolean uidError = false;
 
             if (dataPath.exists()) {
-                // XXX should really do this check for each user.
-                mOutPermissions[1] = 0;
-                FileUtils.getPermissions(dataPath.getPath(), mOutPermissions);
+                int currentUid = 0;
+                try {
+                    StructStat stat = Libcore.os.stat(dataPath.getPath());
+                    currentUid = stat.st_uid;
+                } catch (ErrnoException e) {
+                    Slog.e(TAG, "Couldn't stat path " + dataPath.getPath(), e);
+                }
 
                 // If we have mismatched owners for the data path, we have a problem.
-                if (mOutPermissions[1] != pkg.applicationInfo.uid) {
+                if (currentUid != pkg.applicationInfo.uid) {
                     boolean recovered = false;
-                    if (mOutPermissions[1] == 0) {
+                    if (currentUid == 0) {
                         // The directory somehow became owned by root.  Wow.
                         // This is probably because the system was stopped while
                         // installd was in the middle of messing with its libs
@@ -3825,7 +3833,7 @@
                                     ? "System package " : "Third party package ";
                             String msg = prefix + pkg.packageName
                                     + " has changed from uid: "
-                                    + mOutPermissions[1] + " to "
+                                    + currentUid + " to "
                                     + pkg.applicationInfo.uid + "; old data erased";
                             reportSettingsProblem(Log.WARN, msg);
                             recovered = true;
@@ -3857,11 +3865,11 @@
                     if (!recovered) {
                         pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
                             + pkg.applicationInfo.uid + "/fs_"
-                            + mOutPermissions[1];
+                            + currentUid;
                         pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir;
                         String msg = "Package " + pkg.packageName
                                 + " has mismatched uid: "
-                                + mOutPermissions[1] + " on disk, "
+                                + currentUid + " on disk, "
                                 + pkg.applicationInfo.uid + " in settings";
                         // writer
                         synchronized (mPackages) {
@@ -5148,7 +5156,7 @@
         IActivityManager am = ActivityManagerNative.getDefault();
         if (am != null) {
             try {
-                int[] userIds = userId == UserId.USER_ALL
+                int[] userIds = userId == UserHandle.USER_ALL
                         ? sUserManager.getUserIds() 
                         : new int[] {userId};
                 for (int id : userIds) {
@@ -5163,7 +5171,7 @@
                     // Modify the UID when posting to other users
                     int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
                     if (uid > 0 && id > 0) {
-                        uid = UserId.getUid(id, UserId.getAppId(uid));
+                        uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
                         intent.putExtra(Intent.EXTRA_UID, uid);
                     }
                     intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -5312,13 +5320,13 @@
                 extras.putInt(Intent.EXTRA_UID, removedUid);
                 extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
-                        extras, null, null, UserId.USER_ALL);
+                        extras, null, null, UserHandle.USER_ALL);
             }
             if (addedPackage != null) {
                 Bundle extras = new Bundle(1);
                 extras.putInt(Intent.EXTRA_UID, addedUid);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,
-                        extras, null, null, UserId.USER_ALL);
+                        extras, null, null, UserHandle.USER_ALL);
             }
         }
 
@@ -5344,7 +5352,17 @@
     public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
             int flags, String installerPackageName, Uri verificationURI,
             ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
+        VerificationParams verificationParams = new VerificationParams(verificationURI, null, null,
+                manifestDigest);
+        installPackageWithVerificationAndEncryption(packageURI, observer, flags,
+                installerPackageName, verificationParams, encryptionParams);
+    }
+
+    public void installPackageWithVerificationAndEncryption(Uri packageURI,
+            IPackageInstallObserver observer, int flags, String installerPackageName,
+            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
+                null);
 
         final int uid = Binder.getCallingUid();
 
@@ -5361,7 +5379,7 @@
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName,
-                verificationURI, manifestDigest, encryptionParams);
+                verificationParams, encryptionParams);
         mHandler.sendMessage(msg);
     }
 
@@ -5725,7 +5743,7 @@
         @Override
         void handleStartCopy() throws RemoteException {
             synchronized (mInstallLock) {
-                mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats);
+                mSuccess = getPackageSizeInfoLI(mStats.packageName, mStats.userHandle, mStats);
             }
 
             final boolean mounted;
@@ -5791,8 +5809,7 @@
 
         private final Uri mPackageURI;
         final String installerPackageName;
-        final Uri verificationURI;
-        final ManifestDigest manifestDigest;
+        final VerificationParams verificationParams;
         private InstallArgs mArgs;
         private int mRet;
         private File mTempPackage;
@@ -5800,17 +5817,23 @@
 
         InstallParams(Uri packageURI,
                 IPackageInstallObserver observer, int flags,
-                String installerPackageName, Uri verificationURI, ManifestDigest manifestDigest,
+                String installerPackageName, VerificationParams verificationParams,
                 ContainerEncryptionParams encryptionParams) {
             this.mPackageURI = packageURI;
             this.flags = flags;
             this.observer = observer;
             this.installerPackageName = installerPackageName;
-            this.verificationURI = verificationURI;
-            this.manifestDigest = manifestDigest;
+            this.verificationParams = verificationParams;
             this.encryptionParams = encryptionParams;
         }
 
+        public ManifestDigest getManifestDigest() {
+            if (verificationParams == null) {
+                return null;
+            }
+            return verificationParams.getManifestDigest();
+        }
+
         private int installLocationPolicy(PackageInfoLite pkgLite, int flags) {
             String packageName = pkgLite.packageName;
             int installLocation = pkgLite.installLocation;
@@ -5999,9 +6022,19 @@
 
                     verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALL_FLAGS, flags);
 
-                    if (verificationURI != null) {
-                        verification.putExtra(PackageManager.EXTRA_VERIFICATION_URI,
-                                verificationURI);
+                    if (verificationParams != null) {
+                        if (verificationParams.getVerificationURI() != null) {
+                           verification.putExtra(PackageManager.EXTRA_VERIFICATION_URI,
+                                 verificationParams.getVerificationURI());
+                        }
+                        if (verificationParams.getOriginatingURI() != null) {
+                            verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
+                                  verificationParams.getOriginatingURI());
+                        }
+                        if (verificationParams.getReferrer() != null) {
+                            verification.putExtra(Intent.EXTRA_REFERRER,
+                                  verificationParams.getReferrer());
+                        }
                     }
 
                     final PackageVerificationState verificationState = new PackageVerificationState(
@@ -6337,7 +6370,7 @@
 
         FileInstallArgs(InstallParams params) {
             super(params.getPackageUri(), params.observer, params.flags,
-                    params.installerPackageName, params.manifestDigest);
+                    params.installerPackageName, params.getManifestDigest());
         }
 
         FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) {
@@ -6484,6 +6517,10 @@
                     return false;
                 }
 
+                if (!SELinux.restorecon(newCodeFile)) {
+                    return false;
+                }
+
                 return true;
             }
         }
@@ -6620,7 +6657,7 @@
 
         AsecInstallArgs(InstallParams params) {
             super(params.getPackageUri(), params.observer, params.flags,
-                    params.installerPackageName, params.manifestDigest);
+                    params.installerPackageName, params.getManifestDigest());
         }
 
         AsecInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath,
@@ -7465,6 +7502,9 @@
             FileUtils.setPermissions(
                     tmpPackageFile.getCanonicalPath(), FileUtils.S_IRUSR|FileUtils.S_IWUSR,
                     -1, -1);
+            if (!SELinux.restorecon(tmpPackageFile)) {
+                return null;
+            }
         } catch (IOException e) {
             Slog.e(TAG, "Trouble getting the canoncical path for a temp file.");
             return null;
@@ -7539,11 +7579,11 @@
                 extras.putBoolean(Intent.EXTRA_REPLACING, true);
 
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
-                        extras, null, null, UserId.USER_ALL);
+                        extras, null, null, UserHandle.USER_ALL);
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
-                        extras, null, null, UserId.USER_ALL);
+                        extras, null, null, UserHandle.USER_ALL);
                 sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
-                        null, packageName, null, UserId.USER_ALL);
+                        null, packageName, null, UserHandle.USER_ALL);
             }
         }
         // Force a gc here.
@@ -7576,15 +7616,15 @@
             }
             if (removedPackage != null) {
                 sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
-                        extras, null, null, UserId.USER_ALL);
+                        extras, null, null, UserHandle.USER_ALL);
                 if (fullRemove && !replacing) {
                     sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage,
-                            extras, null, null, UserId.USER_ALL);
+                            extras, null, null, UserHandle.USER_ALL);
                 }
             }
             if (removedUid >= 0) {
                 sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null,
-                        UserId.getUserId(removedUid));
+                        UserHandle.getUserId(removedUid));
             }
         }
     }
@@ -7634,7 +7674,7 @@
                             mSettings.updateSharedUserPermsLPw(deletedPs, mGlobalGids);
                         }
                     }
-                    clearPackagePreferredActivitiesLPw(deletedPs.name);
+                    clearPackagePreferredActivitiesLPw(deletedPs.name, UserHandle.USER_ALL);
                 }
             }
             // can downgrade to reader
@@ -7948,7 +7988,7 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.DELETE_CACHE_FILES, null);
         // Queue up an async operation since the package deletion may take a little while.
-        final int userId = UserId.getCallingUserId();
+        final int userId = UserHandle.getCallingUserId();
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
@@ -7996,12 +8036,12 @@
         return true;
     }
 
-    public void getPackageSizeInfo(final String packageName,
+    public void getPackageSizeInfo(final String packageName, int userHandle,
             final IPackageStatsObserver observer) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.GET_PACKAGE_SIZE, null);
 
-        PackageStats stats = new PackageStats(packageName);
+        PackageStats stats = new PackageStats(packageName, userHandle);
 
         /*
          * Queue up an async operation since the package measurement may take a
@@ -8012,7 +8052,8 @@
         mHandler.sendMessage(msg);
     }
 
-    private boolean getPackageSizeInfoLI(String packageName, PackageStats pStats) {
+    private boolean getPackageSizeInfoLI(String packageName, int userHandle,
+            PackageStats pStats) {
         if (packageName == null) {
             Slog.w(TAG, "Attempt to get size of null packageName.");
             return false;
@@ -8049,7 +8090,7 @@
                 publicSrcDir = applicationInfo.publicSourceDir;
             }
         }
-        int res = mInstaller.getSizeInfo(packageName, p.mPath, publicSrcDir,
+        int res = mInstaller.getSizeInfo(packageName, userHandle, p.mPath, publicSrcDir,
                 asecPath, pStats);
         if (res < 0) {
             return false;
@@ -8101,26 +8142,28 @@
     }
     
     public void addPreferredActivity(IntentFilter filter, int match,
-            ComponentName[] set, ComponentName activity) {
+            ComponentName[] set, ComponentName activity, int userId) {
         // writer
+        int callingUid = Binder.getCallingUid();
+        checkValidCaller(callingUid, userId);
         synchronized (mPackages) {
             if (mContext.checkCallingOrSelfPermission(
                     android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
                     != PackageManager.PERMISSION_GRANTED) {
-                if (getUidTargetSdkVersionLockedLPr(Binder.getCallingUid())
+                if (getUidTargetSdkVersionLockedLPr(callingUid)
                         < Build.VERSION_CODES.FROYO) {
                     Slog.w(TAG, "Ignoring addPreferredActivity() from uid "
-                            + Binder.getCallingUid());
+                            + callingUid);
                     return;
                 }
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
             }
-            
-            Slog.i(TAG, "Adding preferred activity " + activity + ":");
+
+            Slog.i(TAG, "Adding preferred activity " + activity + " for user " + userId + " :");
             filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
             mSettings.mPreferredActivities.addFilter(
-                    new PreferredActivity(filter, match, set, activity));
+                    new PreferredActivity(filter, match, set, activity, userId));
             scheduleWriteSettingsLocked();            
         }
     }
@@ -8156,13 +8199,15 @@
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
             }
-            
+
+            final int callingUserId = UserHandle.getCallingUserId();
             ArrayList<PreferredActivity> removed = null;
             Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
             String action = filter.getAction(0);
             String category = filter.getCategory(0);
             while (it.hasNext()) {
                 PreferredActivity pa = it.next();
+                if (pa.mUserId != callingUserId) continue;
                 if (pa.getAction(0).equals(action) && pa.getCategory(0).equals(category)) {
                     if (removed == null) {
                         removed = new ArrayList<PreferredActivity>();
@@ -8178,7 +8223,7 @@
                     mSettings.mPreferredActivities.removeFilter(pa);
                 }
             }
-            addPreferredActivity(filter, match, set, activity);
+            addPreferredActivity(filter, match, set, activity, callingUserId);
         }
     }
 
@@ -8202,17 +8247,21 @@
                 }
             }
 
-            if (clearPackagePreferredActivitiesLPw(packageName)) {
+            if (clearPackagePreferredActivitiesLPw(packageName, UserHandle.getCallingUserId())) {
                 scheduleWriteSettingsLocked();            
             }
         }
     }
 
-    boolean clearPackagePreferredActivitiesLPw(String packageName) {
+    /** This method takes a specific user id as well as UserHandle.USER_ALL. */
+    boolean clearPackagePreferredActivitiesLPw(String packageName, int userId) {
         ArrayList<PreferredActivity> removed = null;
         Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
         while (it.hasNext()) {
             PreferredActivity pa = it.next();
+            if (userId != UserHandle.USER_ALL && pa.mUserId != userId) {
+                continue;
+            }
             if (pa.mPref.mComponent.getPackageName().equals(packageName)) {
                 if (removed == null) {
                     removed = new ArrayList<PreferredActivity>();
@@ -8234,11 +8283,15 @@
             List<ComponentName> outActivities, String packageName) {
 
         int num = 0;
+        final int userId = UserHandle.getCallingUserId();
         // reader
         synchronized (mPackages) {
             final Iterator<PreferredActivity> it = mSettings.mPreferredActivities.filterIterator();
             while (it.hasNext()) {
                 final PreferredActivity pa = it.next();
+                if (pa.mUserId != userId) {
+                    continue;
+                }
                 if (packageName == null
                         || pa.mPref.mComponent.getPackageName().equals(packageName)) {
                     if (outFilters != null) {
@@ -8303,7 +8356,7 @@
                         + "/" + className);
             }
             // Allow root and verify that userId is not being specified by a different user
-            if (!allowedByPermission && !UserId.isSameApp(uid, pkgSetting.appId)) {
+            if (!allowedByPermission && !UserHandle.isSameApp(uid, pkgSetting.appId)) {
                 throw new SecurityException(
                         "Permission Denial: attempt to change component state from pid="
                         + Binder.getCallingPid()
@@ -8352,7 +8405,7 @@
                 }
             }
             mSettings.writePackageRestrictionsLPr(userId);
-            packageUid = UserId.getUid(userId, pkgSetting.appId);
+            packageUid = UserHandle.getUid(userId, pkgSetting.appId);
             components = mPendingBroadcasts.get(packageName);
             final boolean newPackage = components == null;
             if (newPackage) {
@@ -8401,7 +8454,7 @@
         extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
         extras.putInt(Intent.EXTRA_UID, packageUid);
         sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras, null, null,
-                UserId.getUserId(packageUid));
+                UserHandle.getUserId(packageUid));
     }
 
     public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
@@ -8899,7 +8952,7 @@
         // little while.
         mHandler.post(new Runnable() {
             public void run() {
-                updateExternalMediaStatusInner(mediaStatus, reportStatus);
+                updateExternalMediaStatusInner(mediaStatus, reportStatus, true);
             }
         });
     }
@@ -8909,7 +8962,7 @@
      * Should block until all the ASEC containers are finished being scanned.
      */
     public void scanAvailableAsecs() {
-        updateExternalMediaStatusInner(true, false);
+        updateExternalMediaStatusInner(true, false, false);
     }
 
     /*
@@ -8918,7 +8971,8 @@
      * Please note that we always have to report status if reportStatus has been
      * set to true especially when unloading packages.
      */
-    private void updateExternalMediaStatusInner(boolean isMounted, boolean reportStatus) {
+    private void updateExternalMediaStatusInner(boolean isMounted, boolean reportStatus,
+            boolean externalStorage) {
         // Collection of uids
         int uidArr[] = null;
         // Collection of stale containers
@@ -8956,6 +9010,14 @@
                         continue;
                     }
 
+                    /*
+                     * Skip packages that are not external if we're unmounting
+                     * external storage.
+                     */
+                    if (externalStorage && !isMounted && !isExternal(ps)) {
+                        continue;
+                    }
+
                     final AsecInstallArgs args = new AsecInstallArgs(cid, isForwardLocked(ps));
                     // The package status is changed only if the code path
                     // matches between settings and the container id.
@@ -9018,7 +9080,7 @@
             }
             String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
                     : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
-            sendPackageBroadcast(action, null, extras, null, finishedReceiver, UserId.USER_ALL);
+            sendPackageBroadcast(action, null, extras, null, finishedReceiver, UserHandle.USER_ALL);
         }
     }
 
diff --git a/services/java/com/android/server/pm/PreferredActivity.java b/services/java/com/android/server/pm/PreferredActivity.java
index b100eb1..5539e84 100644
--- a/services/java/com/android/server/pm/PreferredActivity.java
+++ b/services/java/com/android/server/pm/PreferredActivity.java
@@ -33,22 +33,38 @@
     private static final String TAG = "PreferredActivity";
 
     private static final boolean DEBUG_FILTERS = false;
+    static final String ATTR_USER_ID = "userId";
 
     final PreferredComponent mPref;
+    final int mUserId;
 
     PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity) {
+        this(filter, match, set, activity, 0);
+    }
+
+    PreferredActivity(IntentFilter filter, int match, ComponentName[] set, ComponentName activity,
+            int userId) {
         super(filter);
+        mUserId = userId;
         mPref = new PreferredComponent(this, match, set, activity);
     }
 
     PreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException {
+        String userIdString = parser.getAttributeValue(null, ATTR_USER_ID);
+        if (userIdString != null && userIdString.length() > 0) {
+            mUserId = Integer.parseInt(userIdString);
+        } else {
+            // Old format with no userId specified - assume primary user
+            mUserId = 0;
+        }
         mPref = new PreferredComponent(this, parser);
     }
 
     public void writeToXml(XmlSerializer serializer) throws IOException {
+        serializer.attribute(null, ATTR_USER_ID, Integer.toString(mUserId));
         mPref.writeToXml(serializer);
         serializer.startTag(null, "filter");
-        super.writeToXml(serializer);
+            super.writeToXml(serializer);
         serializer.endTag(null, "filter");
     }
 
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index add91d3..cfc0f5c 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -49,7 +49,7 @@
 import android.os.FileUtils;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -2353,7 +2353,7 @@
 
     boolean setPackageStoppedStateLPw(String packageName, boolean stopped,
             boolean allowedByPermission, int uid, int userId) {
-        int appId = UserId.getAppId(uid);
+        int appId = UserHandle.getAppId(uid);
         final PackageSetting pkgSetting = mPackages.get(packageName);
         if (pkgSetting == null) {
             throw new IllegalArgumentException("Unknown package: " + packageName);
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index b55dd24..f5b4053 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -22,6 +22,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 
+import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -34,7 +35,8 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.SystemClock;
-import android.os.UserId;
+import android.os.UserHandle;
+import android.util.AtomicFile;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -55,22 +57,17 @@
 
 public class UserManagerService extends IUserManager.Stub {
 
-    private static final String TAG = "UserManagerService";
+    private static final String LOG_TAG = "UserManagerService";
 
     private static final String TAG_NAME = "name";
-
     private static final String ATTR_FLAGS = "flags";
-
     private static final String ATTR_ICON_PATH = "icon";
-
     private static final String ATTR_ID = "id";
-
+    private static final String ATTR_SERIAL_NO = "serialNumber";
+    private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
     private static final String TAG_USERS = "users";
-
     private static final String TAG_USER = "user";
 
-    private static final String LOG_TAG = "UserManager";
-
     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";
@@ -81,6 +78,7 @@
     private final File mUserListFile;
     private int[] mUserIds;
     private boolean mGuestEnabled;
+    private int mNextSerialNumber;
 
     private Installer mInstaller;
     private File mBaseUserPath;
@@ -125,7 +123,7 @@
 
     @Override
     public List<UserInfo> getUsers() {
-        enforceSystemOrRoot("Only the system can query users");
+        checkManageUsersPermission("query users");
         synchronized (mUsers) {
             ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
             for (int i = 0; i < mUsers.size(); i++) {
@@ -137,13 +135,19 @@
 
     @Override
     public UserInfo getUserInfo(int userId) {
-        enforceSystemOrRoot("Only the system can query user");
+        checkManageUsersPermission("query user");
         synchronized (mUsers) {
-            UserInfo info = mUsers.get(userId);
-            return info;
+            return getUserInfoLocked(userId);
         }
     }
 
+    /*
+     * Should be locked on mUsers before calling this.
+     */
+    private UserInfo getUserInfoLocked(int userId) {
+        return mUsers.get(userId);
+    }
+
     public boolean exists(int userId) {
         synchronized (mUsers) {
             return ArrayUtils.contains(mUserIds, userId);
@@ -152,7 +156,7 @@
 
     @Override
     public void setUserName(int userId, String name) {
-        enforceSystemOrRoot("Only the system can rename users");
+        checkManageUsersPermission("rename users");
         synchronized (mUsers) {
             UserInfo info = mUsers.get(userId);
             if (name != null && !name.equals(info.name)) {
@@ -164,7 +168,7 @@
 
     @Override
     public ParcelFileDescriptor setUserIcon(int userId) {
-        enforceSystemOrRoot("Only the system can update users");
+        checkManageUsersPermission("update users");
         synchronized (mUsers) {
             UserInfo info = mUsers.get(userId);
             if (info == null) return null;
@@ -178,7 +182,7 @@
 
     @Override
     public void setGuestEnabled(boolean enable) {
-        enforceSystemOrRoot("Only the system can enable guest users");
+        checkManageUsersPermission("enable guest users");
         synchronized (mUsers) {
             if (mGuestEnabled != enable) {
                 mGuestEnabled = enable;
@@ -209,21 +213,25 @@
 
     @Override
     public void wipeUser(int userHandle) {
-        enforceSystemOrRoot("Only the system can wipe users");
+        checkManageUsersPermission("wipe user");
         // TODO:
     }
 
     /**
-     * Enforces that only the system UID or root's UID can call a method exposed
-     * via Binder.
+     * Enforces that only the system UID or root's UID or apps that have the
+     * {@link android.Manifest.permission.MANAGE_USERS MANAGE_USERS}
+     * permission can make certain calls to the UserManager.
      *
      * @param message used as message if SecurityException is thrown
      * @throws SecurityException if the caller is not system or root
      */
-    private static final void enforceSystemOrRoot(String message) {
+    private static final void checkManageUsersPermission(String message) {
         final int uid = Binder.getCallingUid();
-        if (uid != Process.SYSTEM_UID && uid != 0) {
-            throw new SecurityException(message);
+        if (uid != Process.SYSTEM_UID && uid != 0
+                && ActivityManager.checkComponentPermission(
+                        android.Manifest.permission.MANAGE_USERS,
+                        uid, -1, true) != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("You need MANAGE_USERS permission to: " + message);
         }
     }
 
@@ -243,7 +251,7 @@
             info.iconPath = file.getAbsolutePath();
             return fd;
         } catch (FileNotFoundException e) {
-            Slog.w(TAG, "Error setting photo for user ", e);
+            Slog.w(LOG_TAG, "Error setting photo for user ", e);
         }
         return null;
     }
@@ -270,8 +278,9 @@
             return;
         }
         FileInputStream fis = null;
+        AtomicFile userListFile = new AtomicFile(mUserListFile);
         try {
-            fis = new FileInputStream(mUserListFile);
+            fis = userListFile.openRead();
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(fis, null);
             int type;
@@ -286,15 +295,26 @@
                 return;
             }
 
+            mNextSerialNumber = -1;
+            if (parser.getName().equals(TAG_USERS)) {
+                String lastSerialNumber = parser.getAttributeValue(null, ATTR_NEXT_SERIAL_NO);
+                if (lastSerialNumber != null) {
+                    mNextSerialNumber = Integer.parseInt(lastSerialNumber);
+                }
+            }
+
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                 if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) {
                     String id = parser.getAttributeValue(null, ATTR_ID);
                     UserInfo user = readUser(Integer.parseInt(id));
                     if (user != null) {
                         mUsers.put(user.id, user);
-                    }
-                    if (user.isGuest()) {
-                        mGuestEnabled = true;
+                        if (user.isGuest()) {
+                            mGuestEnabled = true;
+                        }
+                        if (mNextSerialNumber < 0 || mNextSerialNumber <= user.id) {
+                            mNextSerialNumber = user.id + 1;
+                        }
                     }
                 }
             }
@@ -333,9 +353,9 @@
      */
     private void writeUserLocked(UserInfo userInfo) {
         FileOutputStream fos = null;
+        AtomicFile userFile = new AtomicFile(new File(mUsersDir, userInfo.id + ".xml"));
         try {
-            final File mUserFile = new File(mUsersDir, userInfo.id + ".xml");
-            fos = new FileOutputStream(mUserFile);
+            fos = userFile.startWrite();
             final BufferedOutputStream bos = new BufferedOutputStream(fos);
 
             // XmlSerializer serializer = XmlUtils.serializerInstance();
@@ -346,6 +366,7 @@
 
             serializer.startTag(null, TAG_USER);
             serializer.attribute(null, ATTR_ID, Integer.toString(userInfo.id));
+            serializer.attribute(null, ATTR_SERIAL_NO, Integer.toString(userInfo.serialNumber));
             serializer.attribute(null, ATTR_FLAGS, Integer.toString(userInfo.flags));
             if (userInfo.iconPath != null) {
                 serializer.attribute(null,  ATTR_ICON_PATH, userInfo.iconPath);
@@ -358,30 +379,26 @@
             serializer.endTag(null, TAG_USER);
 
             serializer.endDocument();
-        } catch (IOException ioe) {
+            userFile.finishWrite(fos);
+        } catch (Exception ioe) {
             Slog.e(LOG_TAG, "Error writing user info " + userInfo.id + "\n" + ioe);
-        } finally {
-            if (fos != null) {
-                try {
-                    fos.close();
-                } catch (IOException ioe) {
-                }
-            }
+            userFile.failWrite(fos);
         }
     }
 
     /*
      * Writes the user list file in this format:
      *
-     * <users>
+     * <users nextSerialNumber="3">
      *   <user id="0"></user>
      *   <user id="2"></user>
      * </users>
      */
     private void writeUserListLocked() {
         FileOutputStream fos = null;
+        AtomicFile userListFile = new AtomicFile(mUserListFile);
         try {
-            fos = new FileOutputStream(mUserListFile);
+            fos = userListFile.startWrite();
             final BufferedOutputStream bos = new BufferedOutputStream(fos);
 
             // XmlSerializer serializer = XmlUtils.serializerInstance();
@@ -391,6 +408,7 @@
             serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
 
             serializer.startTag(null, TAG_USERS);
+            serializer.attribute(null, ATTR_NEXT_SERIAL_NO, Integer.toString(mNextSerialNumber));
 
             for (int i = 0; i < mUsers.size(); i++) {
                 UserInfo user = mUsers.valueAt(i);
@@ -402,27 +420,24 @@
             serializer.endTag(null, TAG_USERS);
 
             serializer.endDocument();
-        } catch (IOException ioe) {
+            userListFile.finishWrite(fos);
+        } catch (Exception e) {
+            userListFile.failWrite(fos);
             Slog.e(LOG_TAG, "Error writing user list");
-        } finally {
-            if (fos != null) {
-                try {
-                    fos.close();
-                } catch (IOException ioe) {
-                }
-            }
         }
     }
 
     private UserInfo readUser(int id) {
         int flags = 0;
+        int serialNumber = id;
         String name = null;
         String iconPath = null;
 
         FileInputStream fis = null;
         try {
-            File userFile = new File(mUsersDir, Integer.toString(id) + ".xml");
-            fis = new FileInputStream(userFile);
+            AtomicFile userFile =
+                    new AtomicFile(new File(mUsersDir, Integer.toString(id) + ".xml"));
+            fis = userFile.openRead();
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(fis, null);
             int type;
@@ -442,6 +457,10 @@
                     Slog.e(LOG_TAG, "User id does not match the file name");
                     return null;
                 }
+                String serialNumberValue = parser.getAttributeValue(null, ATTR_SERIAL_NO);
+                if (serialNumberValue != null) {
+                    serialNumber = Integer.parseInt(serialNumberValue);
+                }
                 String flagString = parser.getAttributeValue(null, ATTR_FLAGS);
                 flags = Integer.parseInt(flagString);
                 iconPath = parser.getAttributeValue(null, ATTR_ICON_PATH);
@@ -458,6 +477,7 @@
             }
 
             UserInfo userInfo = new UserInfo(id, name, iconPath, flags);
+            userInfo.serialNumber = serialNumber;
             return userInfo;
 
         } catch (IOException ioe) {
@@ -475,7 +495,7 @@
 
     @Override
     public UserInfo createUser(String name, int flags) {
-        enforceSystemOrRoot("Only the system can create users");
+        checkManageUsersPermission("Only the system can create users");
         int userId = getNextAvailableId();
         UserInfo userInfo = new UserInfo(userId, name, null, flags);
         File userPath = new File(mBaseUserPath, Integer.toString(userId));
@@ -483,6 +503,7 @@
             return null;
         }
         synchronized (mUsers) {
+            userInfo.serialNumber = mNextSerialNumber++;
             mUsers.put(userId, userInfo);
             writeUserListLocked();
             writeUserLocked(userInfo);
@@ -490,8 +511,10 @@
         }
         if (userInfo != null) {
             Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
-            addedIntent.putExtra(Intent.EXTRA_USERID, userInfo.id);
-            mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS);
+            addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
+            mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_USERS);
+            mContext.sendBroadcastAsUser(new Intent(Intent.ACTION_BOOT_COMPLETED),
+                    new UserHandle(userInfo.id));
         }
         return userInfo;
     }
@@ -502,9 +525,34 @@
      * @param id the user's id
      */
     public boolean removeUser(int userHandle) {
-        enforceSystemOrRoot("Only the system can remove users");
+        checkManageUsersPermission("Only the system can remove users");
+        boolean result;
         synchronized (mUsers) {
-            return removeUserLocked(userHandle);
+            result = removeUserLocked(userHandle);
+        }
+        // Let other services shutdown any activity
+        Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
+        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
+        mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_USERS);
+        return result;
+    }
+
+    @Override
+    public int getUserSerialNumber(int userHandle) {
+        synchronized (mUsers) {
+            if (!exists(userHandle)) return -1;
+            return getUserInfoLocked(userHandle).serialNumber;
+        }
+    }
+
+    @Override
+    public int getUserHandle(int userSerialNumber) {
+        synchronized (mUsers) {
+            for (int userId : mUserIds) {
+                if (getUserInfoLocked(userId).serialNumber == userSerialNumber) return userId;
+            }
+            // Not found
+            return -1;
         }
     }
 
@@ -519,17 +567,12 @@
         // Remove this user from the list
         mUsers.remove(userHandle);
         // Remove user file
-        File userFile = new File(mUsersDir, userHandle + ".xml");
+        AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + ".xml"));
         userFile.delete();
         // Update the user list
         writeUserListLocked();
         updateUserIdsLocked();
 
-        // Let other services shutdown any activity
-        Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
-        addedIntent.putExtra(Intent.EXTRA_USERID, userHandle);
-        mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS);
-
         removePackageFolders(userHandle);
         return true;
     }
@@ -539,7 +582,7 @@
             // Don't do it for the primary user, it will become recursive.
             if (userId == 0)
                 continue;
-            mInstaller.createUserData(packageName, UserId.getUid(userId, uid),
+            mInstaller.createUserData(packageName, UserHandle.getUid(userId, uid),
                     userId);
         }
     }
@@ -581,14 +624,16 @@
      * @return
      */
     private int getNextAvailableId() {
-        int i = 0;
-        while (i < Integer.MAX_VALUE) {
-            if (mUsers.indexOfKey(i) < 0) {
-                break;
+        synchronized (mUsers) {
+            int i = 0;
+            while (i < Integer.MAX_VALUE) {
+                if (mUsers.indexOfKey(i) < 0) {
+                    break;
+                }
+                i++;
             }
-            i++;
+            return i;
         }
-        return i;
     }
 
     private boolean createPackageFolders(int id, File userPath) {
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
new file mode 100644
index 0000000..5f917af
--- /dev/null
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -0,0 +1,1177 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import com.android.server.LightsService;
+import com.android.server.TwilightService;
+import com.android.server.TwilightService.TwilightState;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.hardware.SystemSensorManager;
+import android.hardware.display.DisplayManager;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.text.format.DateUtils;
+import android.util.FloatMath;
+import android.util.Slog;
+import android.util.Spline;
+import android.util.TimeUtils;
+import android.view.Display;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+
+/**
+ * Controls the power state of the display.
+ *
+ * Handles the proximity sensor, light sensor, and animations between states
+ * including the screen off animation.
+ *
+ * This component acts independently of the rest of the power manager service.
+ * In particular, it does not share any state and it only communicates
+ * via asynchronous callbacks to inform the power manager that something has
+ * changed.
+ *
+ * Everything this class does internally is serialized on its handler although
+ * it may be accessed by other threads from the outside.
+ *
+ * Note that the power manager service guarantees that it will hold a suspend
+ * blocker as long as the display is not ready.  So most of the work done here
+ * does not need to worry about holding a suspend blocker unless it happens
+ * independently of the display ready signal.
+ *
+ * For debugging, you can make the electron beam and brightness animations run
+ * slower by changing the "animator duration scale" option in Development Settings.
+ */
+final class DisplayPowerController {
+    private static final String TAG = "DisplayPowerController";
+
+    private static boolean DEBUG = false;
+    private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
+    private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
+
+    // If true, uses the electron beam on animation.
+    // We might want to turn this off if we cannot get a guarantee that the screen
+    // actually turns on and starts showing new content after the call to set the
+    // screen state returns.  Playing the animation can also be somewhat slow.
+    private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false;
+
+    // If true, enables the use of the screen auto-brightness adjustment setting.
+    private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT = false;
+
+    // The maximum range of gamma adjustment possible using the screen
+    // auto-brightness adjustment setting.
+    private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
+
+    // If true, enables the use of the current time as an auto-brightness adjustment.
+    // The basic idea here is to expand the dynamic range of auto-brightness
+    // when it is especially dark outside.  The light sensor tends to perform
+    // poorly at low light levels so we compensate for it by making an
+    // assumption about the environment.
+    private static final boolean USE_TWILIGHT_ADJUSTMENT = true;
+
+    // Specifies the maximum magnitude of the time of day adjustment.
+    private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1.5f;
+
+    // The amount of time after or before sunrise over which to start adjusting
+    // the gamma.  We want the change to happen gradually so that it is below the
+    // threshold of perceptibility and so that the adjustment has maximum effect
+    // well after dusk.
+    private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 2;
+
+    private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 250;
+    private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 450;
+
+    private static final int MSG_UPDATE_POWER_STATE = 1;
+    private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
+    private static final int MSG_LIGHT_SENSOR_DEBOUNCED = 3;
+
+    private static final int PROXIMITY_UNKNOWN = -1;
+    private static final int PROXIMITY_NEGATIVE = 0;
+    private static final int PROXIMITY_POSITIVE = 1;
+
+    // Proximity sensor debounce delay in milliseconds.
+    private static final int PROXIMITY_SENSOR_DEBOUNCE_DELAY = 250;
+
+    // Trigger proximity if distance is less than 5 cm.
+    private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
+
+    // Light sensor event rate in microseconds.
+    private static final int LIGHT_SENSOR_RATE = 1000000;
+
+    // Brightness animation ramp rate in brightness units per second.
+    private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
+    private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
+
+    // Filter time constant in milliseconds for computing a moving
+    // average of light samples.  Different constants are used
+    // to calculate the average light level when adapting to brighter or
+    // dimmer environments.
+    // This parameter only controls the filtering of light samples.
+    private static final long BRIGHTENING_LIGHT_TIME_CONSTANT = 600;
+    private static final long DIMMING_LIGHT_TIME_CONSTANT = 4000;
+
+    // Stability requirements in milliseconds for accepting a new brightness
+    // level.  This is used for debouncing the light sensor.  Different constants
+    // are used to debounce the light sensor when adapting to brighter or dimmer
+    // environments.
+    // This parameter controls how quickly brightness changes occur in response to
+    // an observed change in light level.
+    private static final long BRIGHTENING_LIGHT_DEBOUNCE = 2500;
+    private static final long DIMMING_LIGHT_DEBOUNCE = 10000;
+
+    private final Object mLock = new Object();
+
+    // Notifier for sending asynchronous notifications.
+    private final Notifier mNotifier;
+
+    // A suspend blocker.
+    private final SuspendBlocker mSuspendBlocker;
+
+    // Our handler.
+    private final DisplayControllerHandler mHandler;
+
+    // Asynchronous callbacks into the power manager service.
+    // Only invoked from the handler thread while no locks are held.
+    private final Callbacks mCallbacks;
+    private Handler mCallbackHandler;
+
+    // The lights service.
+    private final LightsService mLights;
+
+    // The twilight service.
+    private final TwilightService mTwilight;
+
+    // The sensor manager.
+    private final SensorManager mSensorManager;
+
+    // The proximity sensor, or null if not available or needed.
+    private Sensor mProximitySensor;
+
+    // The light sensor, or null if not available or needed.
+    private Sensor mLightSensor;
+
+    // The dim screen brightness.
+    private final int mScreenBrightnessDimConfig;
+
+    // True if auto-brightness should be used.
+    private boolean mUseSoftwareAutoBrightnessConfig;
+
+    // The auto-brightness spline adjustment.
+    // The brightness values have been scaled to a range of 0..1.
+    private Spline mScreenAutoBrightnessSpline;
+
+    // Amount of time to delay auto-brightness after screen on while waiting for
+    // the light sensor to warm-up in milliseconds.
+    // May be 0 if no warm-up is required.
+    private int mLightSensorWarmUpTimeConfig;
+
+    // The pending power request.
+    // Initially null until the first call to requestPowerState.
+    // Guarded by mLock.
+    private DisplayPowerRequest mPendingRequestLocked;
+
+    // True if a request has been made to wait for the proximity sensor to go negative.
+    // Guarded by mLock.
+    private boolean mPendingWaitForNegativeProximityLocked;
+
+    // True if the pending power request or wait for negative proximity flag
+    // has been changed since the last update occurred.
+    // Guarded by mLock.
+    private boolean mPendingRequestChangedLocked;
+
+    // Set to true when the important parts of the pending power request have been applied.
+    // The important parts are mainly the screen state.  Brightness changes may occur
+    // concurrently.
+    // Guarded by mLock.
+    private boolean mDisplayReadyLocked;
+
+    // Set to true if a power state update is required.
+    // Guarded by mLock.
+    private boolean mPendingUpdatePowerStateLocked;
+
+    /* The following state must only be accessed by the handler thread. */
+
+    // The currently requested power state.
+    // The power controller will progressively update its internal state to match
+    // the requested power state.  Initially null until the first update.
+    private DisplayPowerRequest mPowerRequest;
+
+    // The current power state.
+    // Must only be accessed on the handler thread.
+    private DisplayPowerState mPowerState;
+
+    // True if the device should wait for negative proximity sensor before
+    // waking up the screen.  This is set to false as soon as a negative
+    // proximity sensor measurement is observed or when the device is forced to
+    // go to sleep by the user.  While true, the screen remains off.
+    private boolean mWaitingForNegativeProximity;
+
+    // The actual proximity sensor threshold value.
+    private float mProximityThreshold;
+
+    // Set to true if the proximity sensor listener has been registered
+    // with the sensor manager.
+    private boolean mProximitySensorEnabled;
+
+    // The debounced proximity sensor state.
+    private int mProximity = PROXIMITY_UNKNOWN;
+
+    // The raw non-debounced proximity sensor state.
+    private int mPendingProximity = PROXIMITY_UNKNOWN;
+    private long mPendingProximityDebounceTime;
+
+    // True if the screen was turned off because of the proximity sensor.
+    // When the screen turns on again, we report user activity to the power manager.
+    private boolean mScreenOffBecauseOfProximity;
+
+    // Set to true if the light sensor is enabled.
+    private boolean mLightSensorEnabled;
+
+    // The time when the light sensor was enabled.
+    private long mLightSensorEnableTime;
+
+    // The currently accepted average light sensor value.
+    private float mLightMeasurement;
+
+    // True if the light sensor measurement is valid.
+    private boolean mLightMeasurementValid;
+
+    // The number of light sensor samples that have been collected since the
+    // last time a light sensor reading was accepted.
+    private int mRecentLightSamples;
+
+    // The moving average of recent light sensor values.
+    private float mRecentLightAverage;
+
+    // True if recent light samples are getting brighter than the previous
+    // stable light measurement.
+    private boolean mRecentLightBrightening;
+
+    // The time constant to use for filtering based on whether the
+    // light appears to be brightening or dimming.
+    private long mRecentLightTimeConstant;
+
+    // The most recent light sample.
+    private float mLastLightSample;
+
+    // The time of the most light recent sample.
+    private long mLastLightSampleTime;
+
+    // The time when we accumulated the first recent light sample into mRecentLightSamples.
+    private long mFirstRecentLightSampleTime;
+
+    // The upcoming debounce light sensor time.
+    // This is only valid when mLightMeasurementValue && mRecentLightSamples >= 1.
+    private long mPendingLightSensorDebounceTime;
+
+    // The screen brightness level that has been chosen by the auto-brightness
+    // algorithm.  The actual brightness should ramp towards this value.
+    // We preserve this value even when we stop using the light sensor so
+    // that we can quickly revert to the previous auto-brightness level
+    // while the light sensor warms up.
+    // Use -1 if there is no current auto-brightness value available.
+    private int mScreenAutoBrightness = -1;
+
+    // The last screen auto-brightness gamma.  (For printing in dump() only.)
+    private float mLastScreenAutoBrightnessGamma = 1.0f;
+
+    // True if the screen auto-brightness value is actually being used to
+    // set the display brightness.
+    private boolean mUsingScreenAutoBrightness;
+
+    // Animators.
+    private ObjectAnimator mElectronBeamOnAnimator;
+    private ObjectAnimator mElectronBeamOffAnimator;
+    private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
+
+    // Twilight changed.  We might recalculate auto-brightness values.
+    private boolean mTwilightChanged;
+
+    /**
+     * Creates the display power controller.
+     */
+    public DisplayPowerController(Looper looper, Context context, Notifier notifier,
+            LightsService lights, TwilightService twilight, SuspendBlocker suspendBlocker,
+            Callbacks callbacks, Handler callbackHandler) {
+        mHandler = new DisplayControllerHandler(looper);
+        mNotifier = notifier;
+        mSuspendBlocker = suspendBlocker;
+        mCallbacks = callbacks;
+        mCallbackHandler = callbackHandler;
+
+        mLights = lights;
+        mTwilight = twilight;
+        mSensorManager = new SystemSensorManager(mHandler.getLooper());
+
+        final Resources resources = context.getResources();
+        mScreenBrightnessDimConfig = resources.getInteger(
+                com.android.internal.R.integer.config_screenBrightnessDim);
+        mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_automatic_brightness_available);
+        if (mUseSoftwareAutoBrightnessConfig) {
+            int[] lux = resources.getIntArray(
+                    com.android.internal.R.array.config_autoBrightnessLevels);
+            int[] screenBrightness = resources.getIntArray(
+                    com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
+
+            mScreenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
+            if (mScreenAutoBrightnessSpline == null) {
+                Slog.e(TAG, "Error in config.xml.  config_autoBrightnessLcdBacklightValues "
+                        + "(size " + screenBrightness.length + ") "
+                        + "must be monotic and have exactly one more entry than "
+                        + "config_autoBrightnessLevels (size " + lux.length + ") "
+                        + "which must be strictly increasing.  "
+                        + "Auto-brightness will be disabled.");
+                mUseSoftwareAutoBrightnessConfig = false;
+            }
+
+            mLightSensorWarmUpTimeConfig = resources.getInteger(
+                    com.android.internal.R.integer.config_lightSensorWarmupTime);
+        }
+
+        if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
+            mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+            if (mProximitySensor != null) {
+                mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
+                        TYPICAL_PROXIMITY_THRESHOLD);
+            }
+        }
+
+        if (mUseSoftwareAutoBrightnessConfig
+                && !DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
+            mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+        }
+
+        if (mUseSoftwareAutoBrightnessConfig && USE_TWILIGHT_ADJUSTMENT) {
+            mTwilight.registerListener(mTwilightListener, mHandler);
+        }
+    }
+
+    private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
+        try {
+            final int n = brightness.length;
+            float[] x = new float[n];
+            float[] y = new float[n];
+            y[0] = (float)brightness[0] / PowerManager.BRIGHTNESS_ON;
+            for (int i = 1; i < n; i++) {
+                x[i] = lux[i - 1];
+                y[i] = (float)brightness[i] / PowerManager.BRIGHTNESS_ON;
+            }
+
+            Spline spline = Spline.createMonotoneCubicSpline(x, y);
+            if (false) {
+                Slog.d(TAG, "Auto-brightness spline: " + spline);
+                for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
+                    Slog.d(TAG, String.format("  %7.1f: %7.1f", v, spline.interpolate(v)));
+                }
+            }
+            return spline;
+        } catch (IllegalArgumentException ex) {
+            Slog.e(TAG, "Could not create auto-brightness spline.", ex);
+            return null;
+        }
+    }
+
+    /**
+     * Returns true if the proximity sensor screen-off function is available.
+     */
+    public boolean isProximitySensorAvailable() {
+        return mProximitySensor != null;
+    }
+
+    /**
+     * Requests a new power state.
+     * The controller makes a copy of the provided object and then
+     * begins adjusting the power state to match what was requested.
+     *
+     * @param request The requested power state.
+     * @param waitForNegativeProximity If true, issues a request to wait for
+     * negative proximity before turning the screen back on, assuming the screen
+     * was turned off by the proximity sensor.
+     * @return True if display is ready, false if there are important changes that must
+     * be made asynchronously (such as turning the screen on), in which case the caller
+     * should grab a wake lock, watch for {@link Callbacks#onStateChanged()} then try
+     * the request again later until the state converges.
+     */
+    public boolean requestPowerState(DisplayPowerRequest request,
+            boolean waitForNegativeProximity) {
+        if (DEBUG) {
+            Slog.d(TAG, "requestPowerState: "
+                    + request + ", waitForNegativeProximity=" + waitForNegativeProximity);
+        }
+
+        synchronized (mLock) {
+            boolean changed = false;
+
+            if (waitForNegativeProximity
+                    && !mPendingWaitForNegativeProximityLocked) {
+                mPendingWaitForNegativeProximityLocked = true;
+                changed = true;
+            }
+
+            if (mPendingRequestLocked == null) {
+                mPendingRequestLocked = new DisplayPowerRequest(request);
+                changed = true;
+            } else if (!mPendingRequestLocked.equals(request)) {
+                mPendingRequestLocked.copyFrom(request);
+                changed = true;
+            }
+
+            if (changed) {
+                mDisplayReadyLocked = false;
+            }
+
+            if (changed && !mPendingRequestChangedLocked) {
+                mPendingRequestChangedLocked = true;
+                sendUpdatePowerStateLocked();
+            }
+
+            return mDisplayReadyLocked;
+        }
+    }
+
+    private void sendUpdatePowerState() {
+        synchronized (mLock) {
+            sendUpdatePowerStateLocked();
+        }
+    }
+
+    private void sendUpdatePowerStateLocked() {
+        if (!mPendingUpdatePowerStateLocked) {
+            mPendingUpdatePowerStateLocked = true;
+            Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
+            msg.setAsynchronous(true);
+            mHandler.sendMessage(msg);
+        }
+    }
+
+    private void initialize() {
+        final Executor executor = AsyncTask.THREAD_POOL_EXECUTOR;
+        Display display = DisplayManager.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
+        mPowerState = new DisplayPowerState(new ElectronBeam(display),
+                new PhotonicModulator(executor,
+                        mLights.getLight(LightsService.LIGHT_ID_BACKLIGHT),
+                        mSuspendBlocker));
+
+        mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
+                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
+        mElectronBeamOnAnimator.setDuration(ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS);
+        mElectronBeamOnAnimator.addListener(mAnimatorListener);
+
+        mElectronBeamOffAnimator = ObjectAnimator.ofFloat(
+                mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 1.0f, 0.0f);
+        mElectronBeamOffAnimator.setDuration(ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS);
+        mElectronBeamOffAnimator.addListener(mAnimatorListener);
+
+        mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
+                mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
+    }
+
+    private final Animator.AnimatorListener mAnimatorListener = new Animator.AnimatorListener() {
+        @Override
+        public void onAnimationStart(Animator animation) {
+        }
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            sendUpdatePowerState();
+        }
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+        }
+        @Override
+        public void onAnimationCancel(Animator animation) {
+        }
+    };
+
+    private void updatePowerState() {
+        // Update the power state request.
+        final boolean mustNotify;
+        boolean mustInitialize = false;
+        boolean updateAutoBrightness = mTwilightChanged;
+        mTwilightChanged = false;
+
+        synchronized (mLock) {
+            mPendingUpdatePowerStateLocked = false;
+            if (mPendingRequestLocked == null) {
+                return; // wait until first actual power request
+            }
+
+            if (mPowerRequest == null) {
+                mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
+                mWaitingForNegativeProximity = mPendingWaitForNegativeProximityLocked;
+                mPendingWaitForNegativeProximityLocked = false;
+                mPendingRequestChangedLocked = false;
+                mustInitialize = true;
+            } else if (mPendingRequestChangedLocked) {
+                if (mPowerRequest.screenAutoBrightnessAdjustment
+                        != mPendingRequestLocked.screenAutoBrightnessAdjustment) {
+                    updateAutoBrightness = true;
+                }
+                mPowerRequest.copyFrom(mPendingRequestLocked);
+                mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
+                mPendingWaitForNegativeProximityLocked = false;
+                mPendingRequestChangedLocked = false;
+                mDisplayReadyLocked = false;
+            }
+
+            mustNotify = !mDisplayReadyLocked;
+        }
+
+        // Initialize things the first time the power state is changed.
+        if (mustInitialize) {
+            initialize();
+        }
+
+        // Apply the proximity sensor.
+        if (mProximitySensor != null) {
+            if (mPowerRequest.useProximitySensor
+                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
+                setProximitySensorEnabled(true);
+                if (!mScreenOffBecauseOfProximity
+                        && mProximity == PROXIMITY_POSITIVE) {
+                    mScreenOffBecauseOfProximity = true;
+                    setScreenOn(false);
+                }
+            } else if (mWaitingForNegativeProximity
+                    && mScreenOffBecauseOfProximity
+                    && mProximity == PROXIMITY_POSITIVE
+                    && mPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
+                setProximitySensorEnabled(true);
+            } else {
+                setProximitySensorEnabled(false);
+                mWaitingForNegativeProximity = false;
+            }
+            if (mScreenOffBecauseOfProximity
+                    && mProximity != PROXIMITY_POSITIVE) {
+                mScreenOffBecauseOfProximity = false;
+                setScreenOn(true);
+                sendOnProximityNegative();
+            }
+        } else {
+            mWaitingForNegativeProximity = false;
+        }
+
+        // Turn on the light sensor if needed.
+        if (mLightSensor != null) {
+            setLightSensorEnabled(mPowerRequest.useAutoBrightness
+                    && wantScreenOn(mPowerRequest.screenState), updateAutoBrightness);
+        }
+
+        // Set the screen brightness.
+        if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
+            // Screen is dimmed.  Overrides everything else.
+            animateScreenBrightness(
+                    clampScreenBrightness(mScreenBrightnessDimConfig),
+                    BRIGHTNESS_RAMP_RATE_FAST);
+            mUsingScreenAutoBrightness = false;
+        } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT) {
+            if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
+                // Use current auto-brightness value.
+                animateScreenBrightness(
+                        clampScreenBrightness(mScreenAutoBrightness),
+                        mUsingScreenAutoBrightness ? BRIGHTNESS_RAMP_RATE_SLOW :
+                                BRIGHTNESS_RAMP_RATE_FAST);
+                mUsingScreenAutoBrightness = true;
+            } else {
+                // Light sensor is disabled or not ready yet.
+                // Use the current brightness setting from the request, which is expected
+                // provide a nominal default value for the case where auto-brightness
+                // is not ready yet.
+                animateScreenBrightness(
+                        clampScreenBrightness(mPowerRequest.screenBrightness),
+                        BRIGHTNESS_RAMP_RATE_FAST);
+                mUsingScreenAutoBrightness = false;
+            }
+        } else {
+            // Screen is off.  Don't bother changing the brightness.
+            mUsingScreenAutoBrightness = false;
+        }
+
+        // Animate the screen on or off.
+        if (!mScreenOffBecauseOfProximity) {
+            if (wantScreenOn(mPowerRequest.screenState)) {
+                // Want screen on.
+                // Wait for previous off animation to complete beforehand.
+                // It is relatively short but if we cancel it and switch to the
+                // on animation immediately then the results are pretty ugly.
+                if (!mElectronBeamOffAnimator.isStarted()) {
+                    setScreenOn(true);
+                    if (USE_ELECTRON_BEAM_ON_ANIMATION) {
+                        if (!mElectronBeamOnAnimator.isStarted()) {
+                            if (mPowerState.getElectronBeamLevel() == 1.0f) {
+                                mPowerState.dismissElectronBeam();
+                            } else if (mPowerState.prepareElectronBeam(true)) {
+                                mElectronBeamOnAnimator.start();
+                            } else {
+                                mElectronBeamOnAnimator.end();
+                            }
+                        }
+                    } else {
+                        mPowerState.setElectronBeamLevel(1.0f);
+                        mPowerState.dismissElectronBeam();
+                    }
+                }
+            } else {
+                // Want screen off.
+                // Wait for previous on animation to complete beforehand.
+                if (!mElectronBeamOnAnimator.isStarted()) {
+                    if (!mElectronBeamOffAnimator.isStarted()) {
+                        if (mPowerState.getElectronBeamLevel() == 0.0f) {
+                            setScreenOn(false);
+                        } else if (mPowerState.prepareElectronBeam(false)
+                                && mPowerState.isScreenOn()) {
+                            mElectronBeamOffAnimator.start();
+                        } else {
+                            mElectronBeamOffAnimator.end();
+                        }
+                    }
+                }
+            }
+        }
+
+        // Report whether the display is ready for use.
+        // We mostly care about the screen state here, ignoring brightness changes
+        // which will be handled asynchronously.
+        if (mustNotify
+                && !mElectronBeamOnAnimator.isStarted()
+                && !mElectronBeamOffAnimator.isStarted()
+                && mPowerState.waitUntilClean(mCleanListener)) {
+            synchronized (mLock) {
+                if (!mPendingRequestChangedLocked) {
+                    mDisplayReadyLocked = true;
+                }
+            }
+            sendOnStateChanged();
+        }
+    }
+
+    private void setScreenOn(boolean on) {
+        if (!mPowerState.isScreenOn() == on) {
+            mPowerState.setScreenOn(on);
+            if (on) {
+                mNotifier.onScreenOn();
+            } else {
+                mNotifier.onScreenOff();
+            }
+        }
+    }
+
+    private int clampScreenBrightness(int value) {
+        return Math.min(Math.max(Math.max(value, mScreenBrightnessDimConfig), 0), 255);
+    }
+
+    private void animateScreenBrightness(int target, int rate) {
+        if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
+            mNotifier.onScreenBrightness(target);
+        }
+    }
+
+    private final Runnable mCleanListener = new Runnable() {
+        @Override
+        public void run() {
+            sendUpdatePowerState();
+        }
+    };
+
+    private void setProximitySensorEnabled(boolean enable) {
+        if (enable) {
+            if (!mProximitySensorEnabled) {
+                mProximitySensorEnabled = true;
+                mPendingProximity = PROXIMITY_UNKNOWN;
+                mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
+                        SensorManager.SENSOR_DELAY_NORMAL, mHandler);
+            }
+        } else {
+            if (mProximitySensorEnabled) {
+                mProximitySensorEnabled = false;
+                mProximity = PROXIMITY_UNKNOWN;
+                mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
+                mSensorManager.unregisterListener(mProximitySensorListener);
+            }
+        }
+    }
+
+    private void handleProximitySensorEvent(long time, boolean positive) {
+        if (mPendingProximity == PROXIMITY_NEGATIVE && !positive) {
+            return; // no change
+        }
+        if (mPendingProximity == PROXIMITY_POSITIVE && positive) {
+            return; // no change
+        }
+
+        // Only accept a proximity sensor reading if it remains
+        // stable for the entire debounce delay.
+        mHandler.removeMessages(MSG_PROXIMITY_SENSOR_DEBOUNCED);
+        mPendingProximity = positive ? PROXIMITY_POSITIVE : PROXIMITY_NEGATIVE;
+        mPendingProximityDebounceTime = time + PROXIMITY_SENSOR_DEBOUNCE_DELAY;
+        debounceProximitySensor();
+    }
+
+    private void debounceProximitySensor() {
+        if (mPendingProximity != PROXIMITY_UNKNOWN) {
+            final long now = SystemClock.uptimeMillis();
+            if (mPendingProximityDebounceTime <= now) {
+                mProximity = mPendingProximity;
+                sendUpdatePowerState();
+            } else {
+                Message msg = mHandler.obtainMessage(MSG_PROXIMITY_SENSOR_DEBOUNCED);
+                msg.setAsynchronous(true);
+                mHandler.sendMessageAtTime(msg, mPendingProximityDebounceTime);
+            }
+        }
+    }
+
+    private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness) {
+        if (enable) {
+            if (!mLightSensorEnabled) {
+                updateAutoBrightness = true;
+                mLightSensorEnabled = true;
+                mLightSensorEnableTime = SystemClock.uptimeMillis();
+                mSensorManager.registerListener(mLightSensorListener, mLightSensor,
+                        LIGHT_SENSOR_RATE, mHandler);
+            }
+        } else {
+            if (mLightSensorEnabled) {
+                mLightSensorEnabled = false;
+                mLightMeasurementValid = false;
+                mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
+                mSensorManager.unregisterListener(mLightSensorListener);
+            }
+        }
+        if (updateAutoBrightness) {
+            updateAutoBrightness(false);
+        }
+    }
+
+    private void handleLightSensorEvent(long time, float lux) {
+        // Take the first few readings during the warm-up period and apply them
+        // immediately without debouncing.
+        if (!mLightMeasurementValid
+                || (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
+            mLightMeasurement = lux;
+            mLightMeasurementValid = true;
+            mRecentLightSamples = 0;
+            updateAutoBrightness(true);
+        }
+
+        // Update our moving average.
+        if (lux != mLightMeasurement && (mRecentLightSamples == 0
+                || (lux < mLightMeasurement && mRecentLightBrightening)
+                || (lux > mLightMeasurement && !mRecentLightBrightening))) {
+            // If the newest light sample doesn't seem to be going in the
+            // same general direction as recent samples, then start over.
+            setRecentLight(time, lux, lux > mLightMeasurement);
+        } else if (mRecentLightSamples >= 1) {
+            // Add the newest light sample to the moving average.
+            accumulateRecentLight(time, lux);
+        }
+        if (DEBUG) {
+            Slog.d(TAG, "handleLightSensorEvent: lux=" + lux
+                    + ", mLightMeasurementValid=" + mLightMeasurementValid
+                    + ", mLightMeasurement=" + mLightMeasurement
+                    + ", mRecentLightSamples=" + mRecentLightSamples
+                    + ", mRecentLightAverage=" + mRecentLightAverage
+                    + ", mRecentLightBrightening=" + mRecentLightBrightening
+                    + ", mRecentLightTimeConstant=" + mRecentLightTimeConstant
+                    + ", mFirstRecentLightSampleTime="
+                            + TimeUtils.formatUptime(mFirstRecentLightSampleTime)
+                    + ", mPendingLightSensorDebounceTime="
+                            + TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
+        }
+
+        // Debounce.
+        mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
+        debounceLightSensor();
+    }
+
+    private void setRecentLight(long time, float lux, boolean brightening) {
+        mRecentLightBrightening = brightening;
+        mRecentLightTimeConstant = brightening ?
+                BRIGHTENING_LIGHT_TIME_CONSTANT : DIMMING_LIGHT_TIME_CONSTANT;
+        mRecentLightSamples = 1;
+        mRecentLightAverage = lux;
+        mLastLightSample = lux;
+        mLastLightSampleTime = time;
+        mFirstRecentLightSampleTime = time;
+        mPendingLightSensorDebounceTime = time + (brightening ?
+                BRIGHTENING_LIGHT_DEBOUNCE : DIMMING_LIGHT_DEBOUNCE);
+    }
+
+    private void accumulateRecentLight(long time, float lux) {
+        final long timeDelta = time - mLastLightSampleTime;
+        mRecentLightSamples += 1;
+        mRecentLightAverage += (lux - mRecentLightAverage) *
+                timeDelta / (mRecentLightTimeConstant + timeDelta);
+        mLastLightSample = lux;
+        mLastLightSampleTime = time;
+    }
+
+    private void debounceLightSensor() {
+        if (mLightMeasurementValid && mRecentLightSamples >= 1) {
+            final long now = SystemClock.uptimeMillis();
+            if (mPendingLightSensorDebounceTime <= now) {
+                accumulateRecentLight(now, mLastLightSample);
+                mLightMeasurement = mRecentLightAverage;
+
+                if (DEBUG) {
+                    Slog.d(TAG, "debounceLightSensor: Accepted new measurement "
+                            + mLightMeasurement + " after "
+                            + (now - mFirstRecentLightSampleTime) + " ms based on "
+                            + mRecentLightSamples + " recent samples.");
+                }
+
+                updateAutoBrightness(true);
+
+                // Now that we have debounced the light sensor data, we have the
+                // option of either leaving the sensor in a debounced state or
+                // restarting the debounce cycle by setting mRecentLightSamples to 0.
+                //
+                // If we leave the sensor debounced, then new average light measurements
+                // may be accepted immediately as long as they are trending in the same
+                // direction as they were before.  If the measurements start
+                // jittering or trending in the opposite direction then the debounce
+                // cycle will automatically be restarted.  The benefit is that the
+                // auto-brightness control can be more responsive to changes over a
+                // broad range.
+                //
+                // For now, we choose to be more responsive and leave the following line
+                // commented out.
+                //
+                // mRecentLightSamples = 0;
+            } else {
+                Message msg = mHandler.obtainMessage(MSG_LIGHT_SENSOR_DEBOUNCED);
+                msg.setAsynchronous(true);
+                mHandler.sendMessageAtTime(msg, mPendingLightSensorDebounceTime);
+            }
+        }
+    }
+
+    private void updateAutoBrightness(boolean sendUpdate) {
+        if (!mLightMeasurementValid) {
+            return;
+        }
+
+        float value = mScreenAutoBrightnessSpline.interpolate(mLightMeasurement);
+        float gamma = 1.0f;
+
+        if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
+                && mPowerRequest.screenAutoBrightnessAdjustment != 0.0f) {
+            final float adjGamma = FloatMath.pow(SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA,
+                    Math.min(1.0f, Math.max(-1.0f,
+                            -mPowerRequest.screenAutoBrightnessAdjustment)));
+            gamma *= adjGamma;
+            if (DEBUG) {
+                Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
+            }
+        }
+
+        if (USE_TWILIGHT_ADJUSTMENT) {
+            TwilightState state = mTwilight.getCurrentState();
+            if (state != null && state.isNight()) {
+                final long now = System.currentTimeMillis();
+                final float earlyGamma =
+                        getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise());
+                final float lateGamma =
+                        getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise());
+                gamma *= earlyGamma * lateGamma;
+                if (DEBUG) {
+                    Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma
+                            + ", lateGamma=" + lateGamma);
+                }
+            }
+        }
+
+        if (gamma != 1.0f) {
+            final float in = value;
+            value = FloatMath.pow(value, gamma);
+            if (DEBUG) {
+                Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
+                        + ", in=" + in + ", out=" + value);
+            }
+        }
+
+        int newScreenAutoBrightness = clampScreenBrightness(
+                (int)Math.round(value * PowerManager.BRIGHTNESS_ON));
+        if (mScreenAutoBrightness != newScreenAutoBrightness) {
+            if (DEBUG) {
+                Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
+                        + mScreenAutoBrightness + ", newScreenAutoBrightness="
+                        + newScreenAutoBrightness);
+            }
+
+            mScreenAutoBrightness = newScreenAutoBrightness;
+            mLastScreenAutoBrightnessGamma = gamma;
+            if (sendUpdate) {
+                sendUpdatePowerState();
+            }
+        }
+    }
+
+    private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
+        if (lastSunset < 0 || nextSunrise < 0
+                || now < lastSunset || now > nextSunrise) {
+            return 1.0f;
+        }
+
+        if (now < lastSunset + TWILIGHT_ADJUSTMENT_TIME) {
+            return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
+                    (float)(now - lastSunset) / TWILIGHT_ADJUSTMENT_TIME);
+        }
+
+        if (now > nextSunrise - TWILIGHT_ADJUSTMENT_TIME) {
+            return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
+                    (float)(nextSunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
+        }
+
+        return TWILIGHT_ADJUSTMENT_MAX_GAMMA;
+    }
+
+    private static float lerp(float x, float y, float alpha) {
+        return x + (y - x) * alpha;
+    }
+
+    private void sendOnStateChanged() {
+        mCallbackHandler.post(mOnStateChangedRunnable);
+    }
+
+    private final Runnable mOnStateChangedRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mCallbacks.onStateChanged();
+        }
+    };
+
+    private void sendOnProximityNegative() {
+        mCallbackHandler.post(mOnProximityNegativeRunnable);
+    }
+
+    private final Runnable mOnProximityNegativeRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mCallbacks.onProximityNegative();
+        }
+    };
+
+    public void dump(PrintWriter pw) {
+        synchronized (mLock) {
+            pw.println();
+            pw.println("Display Controller Locked State:");
+            pw.println("  mDisplayReadyLocked=" + mDisplayReadyLocked);
+            pw.println("  mPendingRequestLocked=" + mPendingRequestLocked);
+            pw.println("  mPendingRequestChangedLocked=" + mPendingRequestChangedLocked);
+            pw.println("  mPendingWaitForNegativeProximityLocked="
+                    + mPendingWaitForNegativeProximityLocked);
+            pw.println("  mPendingUpdatePowerStateLocked=" + mPendingUpdatePowerStateLocked);
+        }
+
+        pw.println();
+        pw.println("Display Controller Configuration:");
+        pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
+        pw.println("  mUseSoftwareAutoBrightnessConfig="
+                + mUseSoftwareAutoBrightnessConfig);
+        pw.println("  mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
+        pw.println("  mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
+
+        if (Looper.myLooper() == mHandler.getLooper()) {
+            dumpLocal(pw);
+        } else {
+            final StringWriter out = new StringWriter();
+            final CountDownLatch latch = new CountDownLatch(1);
+            Message msg = Message.obtain(mHandler,  new Runnable() {
+                @Override
+                public void run() {
+                    PrintWriter localpw = new PrintWriter(out);
+                    try {
+                        dumpLocal(localpw);
+                    } finally {
+                        localpw.flush();
+                        latch.countDown();
+                    }
+                }
+            });
+            msg.setAsynchronous(true);
+            mHandler.sendMessage(msg);
+            try {
+                latch.await();
+                pw.print(out.toString());
+            } catch (InterruptedException ex) {
+                pw.println();
+                pw.println("Failed to dump thread state due to interrupted exception!");
+            }
+        }
+    }
+
+    private void dumpLocal(PrintWriter pw) {
+        pw.println();
+        pw.println("Display Controller Thread State:");
+        pw.println("  mPowerRequest=" + mPowerRequest);
+        pw.println("  mWaitingForNegativeProximity=" + mWaitingForNegativeProximity);
+
+        pw.println("  mProximitySensor=" + mProximitySensor);
+        pw.println("  mProximitySensorEnabled=" + mProximitySensorEnabled);
+        pw.println("  mProximityThreshold=" + mProximityThreshold);
+        pw.println("  mProximity=" + proximityToString(mProximity));
+        pw.println("  mPendingProximity=" + proximityToString(mPendingProximity));
+        pw.println("  mPendingProximityDebounceTime="
+                + TimeUtils.formatUptime(mPendingProximityDebounceTime));
+        pw.println("  mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
+
+        pw.println("  mLightSensor=" + mLightSensor);
+        pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
+        pw.println("  mLightSensorEnableTime="
+                + TimeUtils.formatUptime(mLightSensorEnableTime));
+        pw.println("  mLightMeasurement=" + mLightMeasurement);
+        pw.println("  mLightMeasurementValid=" + mLightMeasurementValid);
+        pw.println("  mLastLightSample=" + mLastLightSample);
+        pw.println("  mLastLightSampleTime="
+                + TimeUtils.formatUptime(mLastLightSampleTime));
+        pw.println("  mRecentLightSamples=" + mRecentLightSamples);
+        pw.println("  mRecentLightAverage=" + mRecentLightAverage);
+        pw.println("  mRecentLightBrightening=" + mRecentLightBrightening);
+        pw.println("  mRecentLightTimeConstant=" + mRecentLightTimeConstant);
+        pw.println("  mFirstRecentLightSampleTime="
+                + TimeUtils.formatUptime(mFirstRecentLightSampleTime));
+        pw.println("  mPendingLightSensorDebounceTime="
+                + TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
+        pw.println("  mScreenAutoBrightness=" + mScreenAutoBrightness);
+        pw.println("  mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
+        pw.println("  mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
+        pw.println("  mTwilight.getCurrentState()=" + mTwilight.getCurrentState());
+
+        if (mElectronBeamOnAnimator != null) {
+            pw.println("  mElectronBeamOnAnimator.isStarted()=" +
+                    mElectronBeamOnAnimator.isStarted());
+        }
+        if (mElectronBeamOffAnimator != null) {
+            pw.println("  mElectronBeamOffAnimator.isStarted()=" +
+                    mElectronBeamOffAnimator.isStarted());
+        }
+
+        if (mPowerState != null) {
+            mPowerState.dump(pw);
+        }
+    }
+
+    private static String proximityToString(int state) {
+        switch (state) {
+            case PROXIMITY_UNKNOWN:
+                return "Unknown";
+            case PROXIMITY_NEGATIVE:
+                return "Negative";
+            case PROXIMITY_POSITIVE:
+                return "Positive";
+            default:
+                return Integer.toString(state);
+        }
+    }
+
+    private static boolean wantScreenOn(int state) {
+        switch (state) {
+            case DisplayPowerRequest.SCREEN_STATE_BRIGHT:
+            case DisplayPowerRequest.SCREEN_STATE_DIM:
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Asynchronous callbacks from the power controller to the power manager service.
+     */
+    public interface Callbacks {
+        void onStateChanged();
+        void onProximityNegative();
+    }
+
+    private final class DisplayControllerHandler extends Handler {
+        public DisplayControllerHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_UPDATE_POWER_STATE:
+                    updatePowerState();
+                    break;
+
+                case MSG_PROXIMITY_SENSOR_DEBOUNCED:
+                    debounceProximitySensor();
+                    break;
+
+                case MSG_LIGHT_SENSOR_DEBOUNCED:
+                    debounceLightSensor();
+                    break;
+            }
+        }
+    }
+
+    private final SensorEventListener mProximitySensorListener = new SensorEventListener() {
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            if (mProximitySensorEnabled) {
+                final long time = SystemClock.uptimeMillis();
+                final float distance = event.values[0];
+                boolean positive = distance >= 0.0f && distance < mProximityThreshold;
+                handleProximitySensorEvent(time, positive);
+            }
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+            // Not used.
+        }
+    };
+
+    private final SensorEventListener mLightSensorListener = new SensorEventListener() {
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            if (mLightSensorEnabled) {
+                final long time = SystemClock.uptimeMillis();
+                final float lux = event.values[0];
+                handleLightSensorEvent(time, lux);
+            }
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+            // Not used.
+        }
+    };
+
+    private final TwilightService.TwilightListener mTwilightListener =
+            new TwilightService.TwilightListener() {
+        @Override
+        public void onTwilightStateChanged() {
+            mTwilightChanged = true;
+            updatePowerState();
+        }
+    };
+}
diff --git a/services/java/com/android/server/power/DisplayPowerRequest.java b/services/java/com/android/server/power/DisplayPowerRequest.java
new file mode 100644
index 0000000..2d74292
--- /dev/null
+++ b/services/java/com/android/server/power/DisplayPowerRequest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import android.os.PowerManager;
+
+/**
+ * Describes the requested power state of the display.
+ *
+ * This object is intended to describe the general characteristics of the
+ * power state, such as whether the screen should be on or off and the current
+ * brightness controls leaving the {@link DisplayPowerController} to manage the
+ * details of how the transitions between states should occur.  The goal is for
+ * the {@link PowerManagerService} to focus on the global power state and not
+ * have to micro-manage screen off animations, auto-brightness and other effects.
+ */
+final class DisplayPowerRequest {
+    public static final int SCREEN_STATE_OFF = 0;
+    public static final int SCREEN_STATE_DIM = 1;
+    public static final int SCREEN_STATE_BRIGHT = 2;
+
+    // The requested minimum screen power state: off, dim or bright.
+    public int screenState;
+
+    // If true, the proximity sensor overrides the screen state when an object is
+    // nearby, turning it off temporarily until the object is moved away.
+    public boolean useProximitySensor;
+
+    // The desired screen brightness in the range 0 (minimum / off) to 255 (brightest).
+    // The display power controller may choose to clamp the brightness.
+    // When auto-brightness is enabled, this field should specify a nominal default
+    // value to use while waiting for the light sensor to report enough data.
+    public int screenBrightness;
+
+    // The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter).
+    public float screenAutoBrightnessAdjustment;
+
+    // If true, enables automatic brightness control.
+    public boolean useAutoBrightness;
+
+    public DisplayPowerRequest() {
+        screenState = SCREEN_STATE_BRIGHT;
+        useProximitySensor = false;
+        screenBrightness = PowerManager.BRIGHTNESS_ON;
+        screenAutoBrightnessAdjustment = 0.0f;
+        useAutoBrightness = false;
+    }
+
+    public DisplayPowerRequest(DisplayPowerRequest other) {
+        copyFrom(other);
+    }
+
+    public void copyFrom(DisplayPowerRequest other) {
+        screenState = other.screenState;
+        useProximitySensor = other.useProximitySensor;
+        screenBrightness = other.screenBrightness;
+        screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
+        useAutoBrightness = other.useAutoBrightness;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return o instanceof DisplayPowerRequest
+                && equals((DisplayPowerRequest)o);
+    }
+
+    public boolean equals(DisplayPowerRequest other) {
+        return other != null
+                && screenState == other.screenState
+                && useProximitySensor == other.useProximitySensor
+                && screenBrightness == other.screenBrightness
+                && screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
+                && useAutoBrightness == other.useAutoBrightness;
+    }
+
+    @Override
+    public int hashCode() {
+        return 0; // don't care
+    }
+
+    @Override
+    public String toString() {
+        return "screenState=" + screenState
+                + ", useProximitySensor=" + useProximitySensor
+                + ", screenBrightness=" + screenBrightness
+                + ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
+                + ", useAutoBrightness=" + useAutoBrightness;
+    }
+}
diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/java/com/android/server/power/DisplayPowerState.java
new file mode 100644
index 0000000..64a0462
--- /dev/null
+++ b/services/java/com/android/server/power/DisplayPowerState.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import android.os.Looper;
+import android.os.PowerManager;
+import android.util.FloatProperty;
+import android.util.IntProperty;
+import android.util.Slog;
+import android.view.Choreographer;
+
+import java.io.PrintWriter;
+
+/**
+ * Represents the current display power state and realizes it.
+ *
+ * This component is similar in nature to a {@link View} except that it describes
+ * the properties of a display.  When properties are changed, the component
+ * invalidates itself and posts a callback to the {@link Choreographer} to
+ * apply the changes.  This mechanism enables the display power state to be
+ * animated smoothly by the animation framework.
+ *
+ * This component must only be created or accessed by the {@link Looper} thread
+ * that belongs to the {@link DisplayPowerController}.
+ *
+ * We don't need to worry about holding a suspend blocker here because the
+ * {@link DisplayPowerController} does that for us whenever there is a pending invalidate.
+ */
+final class DisplayPowerState {
+    private static final String TAG = "DisplayPowerState";
+
+    private static boolean DEBUG = false;
+
+    private static final int DIRTY_SCREEN_ON = 1 << 0;
+    private static final int DIRTY_ELECTRON_BEAM = 1 << 1;
+    private static final int DIRTY_BRIGHTNESS = 1 << 2;
+
+    private static final int DIRTY_ALL = 0xffffffff;
+
+    private final Choreographer mChoreographer;
+    private final ElectronBeam mElectronBeam;
+    private final PhotonicModulator mScreenBrightnessModulator;
+
+    private int mDirty;
+    private boolean mScreenOn;
+    private float mElectronBeamLevel;
+    private int mScreenBrightness;
+
+    private Runnable mCleanListener;
+
+    public DisplayPowerState(ElectronBeam electronBean,
+            PhotonicModulator screenBrightnessModulator) {
+        mChoreographer = Choreographer.getInstance();
+        mElectronBeam = electronBean;
+        mScreenBrightnessModulator = screenBrightnessModulator;
+
+        mScreenOn = true;
+        mElectronBeamLevel = 1.0f;
+        mScreenBrightness = PowerManager.BRIGHTNESS_ON;
+        invalidate(DIRTY_ALL);
+    }
+
+    public static final FloatProperty<DisplayPowerState> ELECTRON_BEAM_LEVEL =
+            new FloatProperty<DisplayPowerState>("electronBeamLevel") {
+        @Override
+        public void setValue(DisplayPowerState object, float value) {
+            object.setElectronBeamLevel(value);
+        }
+
+        @Override
+        public Float get(DisplayPowerState object) {
+            return object.getElectronBeamLevel();
+        }
+    };
+
+    public static final IntProperty<DisplayPowerState> SCREEN_BRIGHTNESS =
+            new IntProperty<DisplayPowerState>("screenBrightness") {
+        @Override
+        public void setValue(DisplayPowerState object, int value) {
+            object.setScreenBrightness(value);
+        }
+
+        @Override
+        public Integer get(DisplayPowerState object) {
+            return object.getScreenBrightness();
+        }
+    };
+
+    /**
+     * Sets whether the screen is on or off.
+     */
+    public void setScreenOn(boolean on) {
+        if (mScreenOn != on) {
+            if (DEBUG) {
+                Slog.d(TAG, "setScreenOn: on=" + on);
+            }
+
+            mScreenOn = on;
+            invalidate(DIRTY_SCREEN_ON);
+        }
+    }
+
+    /**
+     * Returns true if the screen is on.
+     */
+    public boolean isScreenOn() {
+        return mScreenOn;
+    }
+
+    /**
+     * Prepares the electron beam to turn on or off.
+     * This method should be called before starting an animation because it
+     * can take a fair amount of time to prepare the electron beam surface.
+     *
+     * @param warmUp True if the electron beam should start warming up.
+     * @return True if the electron beam was prepared.
+     */
+    public boolean prepareElectronBeam(boolean warmUp) {
+        boolean success = mElectronBeam.prepare(warmUp);
+        invalidate(DIRTY_ELECTRON_BEAM);
+        return success;
+    }
+
+    /**
+     * Dismisses the electron beam surface.
+     */
+    public void dismissElectronBeam() {
+        mElectronBeam.dismiss();
+    }
+
+    /**
+     * Sets the level of the electron beam steering current.
+     *
+     * The display is blanked when the level is 0.0.  In normal use, the electron
+     * beam should have a value of 1.0.  The electron beam is unstable in between
+     * these states and the picture quality may be compromised.  For best effect,
+     * the electron beam should be warmed up or cooled off slowly.
+     *
+     * Warning: Electron beam emits harmful radiation.  Avoid direct exposure to
+     * skin or eyes.
+     *
+     * @param level The level, ranges from 0.0 (full off) to 1.0 (full on).
+     */
+    public void setElectronBeamLevel(float level) {
+        if (mElectronBeamLevel != level) {
+            if (DEBUG) {
+                Slog.d(TAG, "setElectronBeamLevel: level=" + level);
+            }
+
+            mElectronBeamLevel = level;
+            invalidate(DIRTY_ELECTRON_BEAM);
+        }
+    }
+
+    /**
+     * Gets the level of the electron beam steering current.
+     */
+    public float getElectronBeamLevel() {
+        return mElectronBeamLevel;
+    }
+
+    /**
+     * Sets the display brightness.
+     *
+     * @param brightness The brightness, ranges from 0 (minimum / off) to 255 (brightest).
+     */
+    public void setScreenBrightness(int brightness) {
+        if (mScreenBrightness != brightness) {
+            if (DEBUG) {
+                Slog.d(TAG, "setScreenBrightness: brightness=" + brightness);
+            }
+
+            mScreenBrightness = brightness;
+            invalidate(DIRTY_BRIGHTNESS);
+        }
+    }
+
+    /**
+     * Gets the screen brightness.
+     */
+    public int getScreenBrightness() {
+        return mScreenBrightness;
+    }
+
+    /**
+     * Returns true if no properties have been invalidated.
+     * Otherwise, returns false and promises to invoke the specified listener
+     * when the properties have all been applied.
+     * The listener always overrides any previously set listener.
+     */
+    public boolean waitUntilClean(Runnable listener) {
+        if (mDirty != 0) {
+            mCleanListener = listener;
+            return false;
+        } else {
+            mCleanListener = null;
+            return true;
+        }
+    }
+
+    public void dump(PrintWriter pw) {
+        pw.println();
+        pw.println("Display Power State:");
+        pw.println("  mDirty=" + Integer.toHexString(mDirty));
+        pw.println("  mScreenOn=" + mScreenOn);
+        pw.println("  mScreenBrightness=" + mScreenBrightness);
+        pw.println("  mElectronBeamLevel=" + mElectronBeamLevel);
+
+        mElectronBeam.dump(pw);
+    }
+
+    private void invalidate(int dirty) {
+        if (mDirty == 0) {
+            mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL,
+                    mTraversalRunnable, null);
+        }
+
+        mDirty |= dirty;
+    }
+
+    private void apply() {
+        if (mDirty != 0) {
+            if ((mDirty & DIRTY_SCREEN_ON) != 0 && !mScreenOn) {
+                PowerManagerService.nativeSetScreenState(false);
+            }
+
+            if ((mDirty & DIRTY_ELECTRON_BEAM) != 0) {
+                mElectronBeam.draw(mElectronBeamLevel);
+            }
+
+            if ((mDirty & (DIRTY_BRIGHTNESS | DIRTY_SCREEN_ON | DIRTY_ELECTRON_BEAM)) != 0) {
+                mScreenBrightnessModulator.setBrightness(mScreenOn ?
+                        (int)(mScreenBrightness * mElectronBeamLevel) : 0);
+            }
+
+            if ((mDirty & DIRTY_SCREEN_ON) != 0 && mScreenOn) {
+                PowerManagerService.nativeSetScreenState(true);
+            }
+
+            mDirty = 0;
+
+            if (mCleanListener != null) {
+                mCleanListener.run();
+            }
+        }
+    }
+
+    private final Runnable mTraversalRunnable = new Runnable() {
+        @Override
+        public void run() {
+            if (mDirty != 0) {
+                apply();
+            }
+        }
+    };
+}
diff --git a/services/java/com/android/server/power/ElectronBeam.java b/services/java/com/android/server/power/ElectronBeam.java
new file mode 100644
index 0000000..aad5a9a
--- /dev/null
+++ b/services/java/com/android/server/power/ElectronBeam.java
@@ -0,0 +1,652 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import android.graphics.Bitmap;
+import android.graphics.PixelFormat;
+import android.opengl.EGL14;
+import android.opengl.EGLConfig;
+import android.opengl.EGLContext;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLSurface;
+import android.opengl.GLES10;
+import android.opengl.GLUtils;
+import android.os.Looper;
+import android.os.Process;
+import android.util.FloatMath;
+import android.util.Slog;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.Surface;
+import android.view.SurfaceSession;
+
+import java.io.PrintWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+/**
+ * Bzzzoooop!  *crackle*
+ *
+ * Animates a screen transition from on to off or off to on by applying
+ * some GL transformations to a screenshot.
+ *
+ * This component must only be created or accessed by the {@link Looper} thread
+ * that belongs to the {@link DisplayPowerController}.
+ */
+final class ElectronBeam {
+    private static final String TAG = "ElectronBeam";
+
+    private static final boolean DEBUG = false;
+
+    // The layer for the electron beam surface.
+    // This is currently hardcoded to be one layer above the boot animation.
+    private static final int ELECTRON_BEAM_LAYER = 0x40000001;
+
+    // The relative proportion of the animation to spend performing
+    // the horizontal stretch effect.  The remainder is spent performing
+    // the vertical stretch effect.
+    private static final float HSTRETCH_DURATION = 0.4f;
+    private static final float VSTRETCH_DURATION = 1.0f - HSTRETCH_DURATION;
+
+    // Set to true when the animation context has been fully prepared.
+    private boolean mPrepared;
+    private boolean mWarmUp;
+
+    private final Display mDisplay;
+    private final DisplayInfo mDisplayInfo = new DisplayInfo();
+    private int mDisplayLayerStack; // layer stack associated with primary display
+    private int mDisplayRotation;
+    private int mDisplayWidth;      // real width, not rotated
+    private int mDisplayHeight;     // real height, not rotated
+    private SurfaceSession mSurfaceSession;
+    private Surface mSurface;
+    private EGLDisplay mEglDisplay;
+    private EGLConfig mEglConfig;
+    private EGLContext mEglContext;
+    private EGLSurface mEglSurface;
+    private boolean mSurfaceVisible;
+
+    // Texture names.  We only use one texture, which contains the screenshot.
+    private final int[] mTexNames = new int[1];
+    private boolean mTexNamesGenerated;
+
+    // Vertex and corresponding texture coordinates.
+    // We have 4 2D vertices, so 8 elements.  The vertices form a quad.
+    private final FloatBuffer mVertexBuffer = createNativeFloatBuffer(8);
+    private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
+
+    public ElectronBeam(Display display) {
+        mDisplay = display;
+    }
+
+    /**
+     * Warms up the electron beam in preparation for turning on or off.
+     * This method prepares a GL context, and captures a screen shot.
+     *
+     * @param warmUp True if the electron beam is about to be turned on, false if
+     * it is about to be turned off.
+     * @return True if the electron beam is ready, false if it is uncontrollable.
+     */
+    public boolean prepare(boolean warmUp) {
+        if (DEBUG) {
+            Slog.d(TAG, "prepare: warmUp=" + warmUp);
+        }
+
+        mWarmUp = warmUp;
+
+        // Get the display size and adjust it for rotation.
+        mDisplay.getDisplayInfo(mDisplayInfo);
+        mDisplayLayerStack = mDisplay.getLayerStack();
+        mDisplayRotation = mDisplayInfo.rotation;
+        if (mDisplayRotation == Surface.ROTATION_90
+                || mDisplayRotation == Surface.ROTATION_270) {
+            mDisplayWidth = mDisplayInfo.logicalHeight;
+            mDisplayHeight = mDisplayInfo.logicalWidth;
+        } else {
+            mDisplayWidth = mDisplayInfo.logicalWidth;
+            mDisplayHeight = mDisplayInfo.logicalHeight;
+        }
+
+        // Prepare the surface for drawing.
+        if (!createEglContext()
+                || !createEglSurface()
+                || !captureScreenshotTextureAndSetViewport()) {
+            dismiss();
+            return false;
+        }
+
+        mPrepared = true;
+        return true;
+    }
+
+    /**
+     * Dismisses the electron beam animation surface and cleans up.
+     *
+     * To prevent stray photons from leaking out after the electron beam has been
+     * turned off, it is a good idea to defer dismissing the animation until the
+     * electron beam has been turned back on fully.
+     */
+    public void dismiss() {
+        if (DEBUG) {
+            Slog.d(TAG, "dismiss");
+        }
+
+        destroyScreenshotTexture();
+        destroyEglSurface();
+        mPrepared = false;
+    }
+
+    /**
+     * Draws an animation frame showing the electron beam activated at the
+     * specified level.
+     *
+     * @param level The electron beam level.
+     * @return True if successful.
+     */
+    public boolean draw(float level) {
+        if (DEBUG) {
+            Slog.d(TAG, "drawFrame: level=" + level);
+        }
+
+        if (!attachEglContext()) {
+            return false;
+        }
+        try {
+            // Clear frame to solid black.
+            GLES10.glClearColor(0f, 0f, 0f, 1f);
+            GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT);
+
+            // Draw the frame.
+            if (level < HSTRETCH_DURATION) {
+                drawHStretch(1.0f - (level / HSTRETCH_DURATION));
+            } else {
+                drawVStretch(1.0f - ((level - HSTRETCH_DURATION) / VSTRETCH_DURATION));
+            }
+            if (checkGlErrors("drawFrame")) {
+                return false;
+            }
+
+            EGL14.eglSwapBuffers(mEglDisplay, mEglSurface);
+        } finally {
+            detachEglContext();
+        }
+
+        return showEglSurface();
+    }
+
+    /**
+     * Draws a frame where the content of the electron beam is collapsing inwards upon
+     * itself vertically with red / green / blue channels dispersing and eventually
+     * merging down to a single horizontal line.
+     *
+     * @param stretch The stretch factor.  0.0 is no collapse, 1.0 is full collapse.
+     */
+    private void drawVStretch(float stretch) {
+        // compute interpolation scale factors for each color channel
+        final float ar = scurve(stretch, 7.5f);
+        final float ag = scurve(stretch, 8.0f);
+        final float ab = scurve(stretch, 8.5f);
+        if (DEBUG) {
+            Slog.d(TAG, "drawVStretch: stretch=" + stretch
+                    + ", ar=" + ar + ", ag=" + ag + ", ab=" + ab);
+        }
+
+        // set blending
+        GLES10.glBlendFunc(GLES10.GL_ONE, GLES10.GL_ONE);
+        GLES10.glEnable(GLES10.GL_BLEND);
+
+        // bind vertex buffer
+        GLES10.glVertexPointer(2, GLES10.GL_FLOAT, 0, mVertexBuffer);
+        GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
+
+        // bind texture and set blending for drawing planes
+        GLES10.glBindTexture(GLES10.GL_TEXTURE_2D, mTexNames[0]);
+        GLES10.glTexEnvx(GLES10.GL_TEXTURE_ENV, GLES10.GL_TEXTURE_ENV_MODE,
+                mWarmUp ? GLES10.GL_MODULATE : GLES10.GL_REPLACE);
+        GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D,
+                GLES10.GL_TEXTURE_MAG_FILTER, GLES10.GL_LINEAR);
+        GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D,
+                GLES10.GL_TEXTURE_MIN_FILTER, GLES10.GL_LINEAR);
+        GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D,
+                GLES10.GL_TEXTURE_WRAP_S, GLES10.GL_CLAMP_TO_EDGE);
+        GLES10.glTexParameterx(GLES10.GL_TEXTURE_2D,
+                GLES10.GL_TEXTURE_WRAP_T, GLES10.GL_CLAMP_TO_EDGE);
+        GLES10.glEnable(GLES10.GL_TEXTURE_2D);
+        GLES10.glTexCoordPointer(2, GLES10.GL_FLOAT, 0, mTexCoordBuffer);
+        GLES10.glEnableClientState(GLES10.GL_TEXTURE_COORD_ARRAY);
+
+        // draw the red plane
+        setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ar);
+        GLES10.glColorMask(true, false, false, true);
+        GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
+
+        // draw the green plane
+        setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag);
+        GLES10.glColorMask(false, true, false, true);
+        GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
+
+        // draw the blue plane
+        setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ab);
+        GLES10.glColorMask(false, false, true, true);
+        GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
+
+        // clean up after drawing planes
+        GLES10.glDisable(GLES10.GL_TEXTURE_2D);
+        GLES10.glDisableClientState(GLES10.GL_TEXTURE_COORD_ARRAY);
+        GLES10.glColorMask(true, true, true, true);
+
+        // draw the white highlight (we use the last vertices)
+        if (!mWarmUp) {
+            GLES10.glColor4f(ag, ag, ag, 1.0f);
+            GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
+        }
+
+        // clean up
+        GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY);
+        GLES10.glDisable(GLES10.GL_BLEND);
+    }
+
+    /**
+     * Draws a frame where the electron beam has been stretched out into
+     * a thin white horizontal line that fades as it expands outwards.
+     *
+     * @param stretch The stretch factor.  0.0 is no stretch / no fade,
+     * 1.0 is maximum stretch / maximum fade.
+     */
+    private void drawHStretch(float stretch) {
+        // compute interpolation scale factor
+        final float ag = scurve(stretch, 8.0f);
+        if (DEBUG) {
+            Slog.d(TAG, "drawHStretch: stretch=" + stretch + ", ag=" + ag);
+        }
+
+        if (stretch < 1.0f) {
+            // bind vertex buffer
+            GLES10.glVertexPointer(2, GLES10.GL_FLOAT, 0, mVertexBuffer);
+            GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
+
+            // draw narrow fading white line
+            setHStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag);
+            GLES10.glColor4f(1.0f - ag, 1.0f - ag, 1.0f - ag, 1.0f);
+            GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
+
+            // clean up
+            GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY);
+        }
+    }
+
+    private static void setVStretchQuad(FloatBuffer vtx, float dw, float dh, float a) {
+        final float w = dw + (dw * a);
+        final float h = dh - (dh * a);
+        final float x = (dw - w) * 0.5f;
+        final float y = (dh - h) * 0.5f;
+        setQuad(vtx, x, y, w, h);
+    }
+
+    private static void setHStretchQuad(FloatBuffer vtx, float dw, float dh, float a) {
+        final float w = dw + (dw * a);
+        final float h = 1.0f;
+        final float x = (dw - w) * 0.5f;
+        final float y = (dh - h) * 0.5f;
+        setQuad(vtx, x, y, w, h);
+    }
+
+    private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
+        if (DEBUG) {
+            Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
+        }
+        vtx.put(0, x);
+        vtx.put(1, y);
+        vtx.put(2, x);
+        vtx.put(3, y + h);
+        vtx.put(4, x + w);
+        vtx.put(5, y + h);
+        vtx.put(6, x + w);
+        vtx.put(7, y);
+    }
+
+    private boolean captureScreenshotTextureAndSetViewport() {
+        // TODO: Use a SurfaceTexture to avoid the extra texture upload.
+        Bitmap bitmap = Surface.screenshot(mDisplayWidth, mDisplayHeight,
+                0, ELECTRON_BEAM_LAYER - 1);
+        if (bitmap == null) {
+            Slog.e(TAG, "Could not take a screenshot!");
+            return false;
+        }
+        try {
+            if (!attachEglContext()) {
+                return false;
+            }
+            try {
+                if (!mTexNamesGenerated) {
+                    GLES10.glGenTextures(1, mTexNames, 0);
+                    if (checkGlErrors("glGenTextures")) {
+                        return false;
+                    }
+                    mTexNamesGenerated = true;
+                }
+
+                GLES10.glBindTexture(GLES10.GL_TEXTURE_2D, mTexNames[0]);
+                if (checkGlErrors("glBindTexture")) {
+                    return false;
+                }
+
+                float u = 1.0f;
+                float v = 1.0f;
+                GLUtils.texImage2D(GLES10.GL_TEXTURE_2D, 0, bitmap, 0);
+                if (checkGlErrors("glTexImage2D, first try", false)) {
+                    // Try a power of two size texture instead.
+                    int tw = nextPowerOfTwo(mDisplayWidth);
+                    int th = nextPowerOfTwo(mDisplayHeight);
+                    int format = GLUtils.getInternalFormat(bitmap);
+                    GLES10.glTexImage2D(GLES10.GL_TEXTURE_2D, 0,
+                            format, tw, th, 0,
+                            format, GLES10.GL_UNSIGNED_BYTE, null);
+                    if (checkGlErrors("glTexImage2D, second try")) {
+                        return false;
+                    }
+
+                    GLUtils.texSubImage2D(GLES10.GL_TEXTURE_2D, 0, 0, 0, bitmap);
+                    if (checkGlErrors("glTexSubImage2D")) {
+                        return false;
+                    }
+
+                    u = (float)mDisplayWidth / tw;
+                    v = (float)mDisplayHeight / th;
+                }
+
+                // Set up texture coordinates for a quad.
+                // We might need to change this if the texture ends up being
+                // a different size from the display for some reason.
+                mTexCoordBuffer.put(0, 0f);
+                mTexCoordBuffer.put(1, v);
+                mTexCoordBuffer.put(2, 0f);
+                mTexCoordBuffer.put(3, 0f);
+                mTexCoordBuffer.put(4, u);
+                mTexCoordBuffer.put(5, 0f);
+                mTexCoordBuffer.put(6, u);
+                mTexCoordBuffer.put(7, v);
+
+                // Set up our viewport.
+                GLES10.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
+                GLES10.glMatrixMode(GLES10.GL_PROJECTION);
+                GLES10.glLoadIdentity();
+                GLES10.glOrthof(0, mDisplayWidth, 0, mDisplayHeight, 0, 1);
+                GLES10.glMatrixMode(GLES10.GL_MODELVIEW);
+                GLES10.glLoadIdentity();
+                GLES10.glMatrixMode(GLES10.GL_TEXTURE);
+                GLES10.glLoadIdentity();
+            } finally {
+                detachEglContext();
+            }
+        } finally {
+            bitmap.recycle();
+        }
+        return true;
+    }
+
+    private void destroyScreenshotTexture() {
+        if (mTexNamesGenerated) {
+            mTexNamesGenerated = false;
+            if (attachEglContext()) {
+                try {
+                    GLES10.glDeleteTextures(1, mTexNames, 0);
+                    checkGlErrors("glDeleteTextures");
+                } finally {
+                    detachEglContext();
+                }
+            }
+        }
+    }
+
+    private boolean createEglContext() {
+        if (mEglDisplay == null) {
+            mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
+            if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
+                logEglError("eglGetDisplay");
+                return false;
+            }
+
+            int[] version = new int[2];
+            if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) {
+                mEglDisplay = null;
+                logEglError("eglInitialize");
+                return false;
+            }
+        }
+
+        if (mEglConfig == null) {
+            int[] eglConfigAttribList = new int[] {
+                    EGL14.EGL_RED_SIZE, 8,
+                    EGL14.EGL_GREEN_SIZE, 8,
+                    EGL14.EGL_BLUE_SIZE, 8,
+                    EGL14.EGL_ALPHA_SIZE, 8,
+                    EGL14.EGL_NONE
+            };
+            int[] numEglConfigs = new int[1];
+            EGLConfig[] eglConfigs = new EGLConfig[1];
+            if (!EGL14.eglChooseConfig(mEglDisplay, eglConfigAttribList, 0,
+                    eglConfigs, 0, eglConfigs.length, numEglConfigs, 0)) {
+                logEglError("eglChooseConfig");
+                return false;
+            }
+            mEglConfig = eglConfigs[0];
+        }
+
+        if (mEglContext == null) {
+            int[] eglContextAttribList = new int[] {
+                    EGL14.EGL_NONE
+            };
+            mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
+                    EGL14.EGL_NO_CONTEXT, eglContextAttribList, 0);
+            if (mEglContext == null) {
+                logEglError("eglCreateContext");
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /* not used because it is too expensive to create / destroy contexts all of the time
+    private void destroyEglContext() {
+        if (mEglContext != null) {
+            if (!EGL14.eglDestroyContext(mEglDisplay, mEglContext)) {
+                logEglError("eglDestroyContext");
+            }
+            mEglContext = null;
+        }
+    }*/
+
+    private boolean createEglSurface() {
+        if (mSurfaceSession == null) {
+            mSurfaceSession = new SurfaceSession();
+        }
+
+        Surface.openTransaction();
+        try {
+            if (mSurface == null) {
+                try {
+                    mSurface = new Surface(mSurfaceSession, Process.myPid(),
+                            "ElectronBeam", mDisplayLayerStack, mDisplayWidth, mDisplayHeight,
+                            PixelFormat.OPAQUE, Surface.OPAQUE | Surface.HIDDEN);
+                } catch (Surface.OutOfResourcesException ex) {
+                    Slog.e(TAG, "Unable to create surface.", ex);
+                    return false;
+                }
+            }
+
+            mSurface.setSize(mDisplayWidth, mDisplayHeight);
+
+            switch (mDisplayRotation) {
+                case Surface.ROTATION_0:
+                    mSurface.setPosition(0, 0);
+                    mSurface.setMatrix(1, 0, 0, 1);
+                    break;
+                case Surface.ROTATION_90:
+                    mSurface.setPosition(0, mDisplayWidth);
+                    mSurface.setMatrix(0, -1, 1, 0);
+                    break;
+                case Surface.ROTATION_180:
+                    mSurface.setPosition(mDisplayWidth, mDisplayHeight);
+                    mSurface.setMatrix(-1, 0, 0, -1);
+                    break;
+                case Surface.ROTATION_270:
+                    mSurface.setPosition(mDisplayHeight, 0);
+                    mSurface.setMatrix(0, 1, -1, 0);
+                    break;
+            }
+        } finally {
+            Surface.closeTransaction();
+        }
+
+        if (mEglSurface == null) {
+            int[] eglSurfaceAttribList = new int[] {
+                    EGL14.EGL_NONE
+            };
+            mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface,
+                    eglSurfaceAttribList, 0);
+            if (mEglSurface == null) {
+                logEglError("eglCreateWindowSurface");
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void destroyEglSurface() {
+        if (mEglSurface != null) {
+            if (!EGL14.eglDestroySurface(mEglDisplay, mEglSurface)) {
+                logEglError("eglDestroySurface");
+            }
+            mEglSurface = null;
+        }
+
+        if (mSurface != null) {
+            Surface.openTransaction();
+            try {
+                mSurface.destroy();
+            } finally {
+                Surface.closeTransaction();
+            }
+            mSurface = null;
+            mSurfaceVisible = false;
+        }
+    }
+
+    private boolean showEglSurface() {
+        if (!mSurfaceVisible) {
+            Surface.openTransaction();
+            try {
+                mSurface.setLayer(ELECTRON_BEAM_LAYER);
+                mSurface.show();
+            } finally {
+                Surface.closeTransaction();
+            }
+            mSurfaceVisible = true;
+        }
+        return true;
+    }
+
+    private boolean attachEglContext() {
+        if (mEglSurface == null) {
+            return false;
+        }
+        if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+            logEglError("eglMakeCurrent");
+            return false;
+        }
+        return true;
+    }
+
+    private void detachEglContext() {
+        if (mEglDisplay != null) {
+            EGL14.eglMakeCurrent(mEglDisplay,
+                    EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
+        }
+    }
+
+    /**
+     * Interpolates a value in the range 0 .. 1 along a sigmoid curve
+     * yielding a result in the range 0 .. 1 scaled such that:
+     * scurve(0) == 0, scurve(0.5) == 0.5, scurve(1) == 1.
+     */
+    private static float scurve(float value, float s) {
+        // A basic sigmoid has the form y = 1.0f / FloatMap.exp(-x * s).
+        // Here we take the input datum and shift it by 0.5 so that the
+        // domain spans the range -0.5 .. 0.5 instead of 0 .. 1.
+        final float x = value - 0.5f;
+
+        // Next apply the sigmoid function to the scaled value
+        // which produces a value in the range 0 .. 1 so we subtract
+        // 0.5 to get a value in the range -0.5 .. 0.5 instead.
+        final float y = sigmoid(x, s) - 0.5f;
+
+        // To obtain the desired boundary conditions we need to scale
+        // the result so that it fills a range of -1 .. 1.
+        final float v = sigmoid(0.5f, s) - 0.5f;
+
+        // And finally remap the value back to a range of 0 .. 1.
+        return y / v * 0.5f + 0.5f;
+    }
+
+    private static float sigmoid(float x, float s) {
+        return 1.0f / (1.0f + FloatMath.exp(-x * s));
+    }
+
+    private static int nextPowerOfTwo(int value) {
+        return 1 << (32 - Integer.numberOfLeadingZeros(value));
+    }
+
+    private static FloatBuffer createNativeFloatBuffer(int size) {
+        ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
+        bb.order(ByteOrder.nativeOrder());
+        return bb.asFloatBuffer();
+    }
+
+    private static void logEglError(String func) {
+        Slog.e(TAG, func + " failed: error " + EGL14.eglGetError(), new Throwable());
+    }
+
+    private static boolean checkGlErrors(String func) {
+        return checkGlErrors(func, true);
+    }
+
+    private static boolean checkGlErrors(String func, boolean log) {
+        boolean hadError = false;
+        int error;
+        while ((error = GLES10.glGetError()) != GLES10.GL_NO_ERROR) {
+            if (log) {
+                Slog.e(TAG, func + " failed: error " + error, new Throwable());
+            }
+            hadError = true;
+        }
+        return hadError;
+    }
+
+    public void dump(PrintWriter pw) {
+        pw.println();
+        pw.println("Electron Beam State:");
+        pw.println("  mPrepared=" + mPrepared);
+        pw.println("  mWarmUp=" + mWarmUp);
+        pw.println("  mDisplayLayerStack=" + mDisplayLayerStack);
+        pw.println("  mDisplayRotation=" + mDisplayRotation);
+        pw.println("  mDisplayWidth=" + mDisplayWidth);
+        pw.println("  mDisplayHeight=" + mDisplayHeight);
+        pw.println("  mSurfaceVisible=" + mSurfaceVisible);
+    }
+}
diff --git a/services/java/com/android/server/power/Notifier.java b/services/java/com/android/server/power/Notifier.java
new file mode 100644
index 0000000..9d928e5
--- /dev/null
+++ b/services/java/com/android/server/power/Notifier.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import com.android.internal.app.IBatteryStats;
+import com.android.server.EventLogTags;
+
+import android.app.ActivityManagerNative;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.BatteryStats;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.WorkSource;
+import android.util.EventLog;
+import android.util.Slog;
+import android.view.WindowManagerPolicy;
+import android.view.WindowManagerPolicy.ScreenOnListener;
+
+/**
+ * Sends broadcasts about important power state changes.
+ *
+ * This methods of this class may be called by the power manager service while
+ * its lock is being held.  Internally it takes care of sending broadcasts to
+ * notify other components of the system or applications asynchronously.
+ *
+ * The notifier is designed to collapse unnecessary broadcasts when it is not
+ * possible for the system to have observed an intermediate state.
+ *
+ * For example, if the device wakes up, goes to sleep and wakes up again immediately
+ * before the go to sleep broadcast has been sent, then no broadcast will be
+ * sent about the system going to sleep and waking up.
+ */
+final class Notifier {
+    private static final String TAG = "PowerManagerNotifier";
+
+    private static final boolean DEBUG = false;
+
+    private static final int POWER_STATE_UNKNOWN = 0;
+    private static final int POWER_STATE_AWAKE = 1;
+    private static final int POWER_STATE_ASLEEP = 2;
+
+    private static final int MSG_USER_ACTIVITY = 1;
+    private static final int MSG_BROADCAST = 2;
+
+    private final Object mLock = new Object();
+
+    private final Context mContext;
+    private final IBatteryStats mBatteryStats;
+    private final SuspendBlocker mSuspendBlocker;
+    private final WindowManagerPolicy mPolicy;
+    private final ScreenOnListener mScreenOnListener;
+
+    private final NotifierHandler mHandler;
+    private final Intent mScreenOnIntent;
+    private final Intent mScreenOffIntent;
+
+    // The current power state.
+    private int mActualPowerState;
+    private int mLastGoToSleepReason;
+
+    // The currently broadcasted power state.  This reflects what other parts of the
+    // system have observed.
+    private int mBroadcastedPowerState;
+    private boolean mBroadcastInProgress;
+    private long mBroadcastStartTime;
+
+    // True if a user activity message should be sent.
+    private boolean mUserActivityPending;
+
+    public Notifier(Looper looper, Context context, IBatteryStats batteryStats,
+            SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
+            ScreenOnListener screenOnListener) {
+        mContext = context;
+        mBatteryStats = batteryStats;
+        mSuspendBlocker = suspendBlocker;
+        mPolicy = policy;
+        mScreenOnListener = screenOnListener;
+
+        mHandler = new NotifierHandler(looper);
+        mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
+        mScreenOnIntent.addFlags(
+                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
+        mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
+        mScreenOffIntent.addFlags(
+                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
+    }
+
+    /**
+     * Called when a wake lock is acquired.
+     */
+    public void onWakeLockAcquired(int flags, String tag, int ownerUid, int ownerPid,
+            WorkSource workSource) {
+        if (DEBUG) {
+            Slog.d(TAG, "onWakeLockAcquired: flags=" + flags + ", tag=\"" + tag
+                    + "\", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
+                    + ", workSource=" + workSource);
+        }
+
+        try {
+            final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+            if (workSource != null) {
+                mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType);
+            } else {
+                mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType);
+            }
+        } catch (RemoteException ex) {
+            // Ignore
+        }
+    }
+
+    /**
+     * Called when a wake lock is released.
+     */
+    public void onWakeLockReleased(int flags, String tag, int ownerUid, int ownerPid,
+            WorkSource workSource) {
+        if (DEBUG) {
+            Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag
+                    + "\", ownerUid=" + ownerUid + ", ownerPid=" + ownerPid
+                    + ", workSource=" + workSource);
+        }
+
+        try {
+            final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+            if (workSource != null) {
+                mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, monitorType);
+            } else {
+                mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, monitorType);
+            }
+        } catch (RemoteException ex) {
+            // Ignore
+        }
+    }
+
+    private static int getBatteryStatsWakeLockMonitorType(int flags) {
+        switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
+            case PowerManager.PARTIAL_WAKE_LOCK:
+            case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
+                return BatteryStats.WAKE_TYPE_PARTIAL;
+            default:
+                return BatteryStats.WAKE_TYPE_FULL;
+        }
+    }
+
+    /**
+     * Called when the screen is turned on.
+     */
+    public void onScreenOn() {
+        if (DEBUG) {
+            Slog.d(TAG, "onScreenOn");
+        }
+
+        try {
+            mBatteryStats.noteScreenOn();
+        } catch (RemoteException ex) {
+            // Ignore
+        }
+    }
+
+    /**
+     * Called when the screen is turned off.
+     */
+    public void onScreenOff() {
+        if (DEBUG) {
+            Slog.d(TAG, "onScreenOff");
+        }
+
+        try {
+            mBatteryStats.noteScreenOff();
+        } catch (RemoteException ex) {
+            // Ignore
+        }
+    }
+
+    /**
+     * Called when the screen changes brightness.
+     */
+    public void onScreenBrightness(int brightness) {
+        if (DEBUG) {
+            Slog.d(TAG, "onScreenBrightness: brightness=" + brightness);
+        }
+
+        try {
+            mBatteryStats.noteScreenBrightness(brightness);
+        } catch (RemoteException ex) {
+            // Ignore
+        }
+    }
+
+    /**
+     * Called when the device is waking up from sleep and the
+     * display is about to be turned on.
+     */
+    public void onWakeUpStarted() {
+        if (DEBUG) {
+            Slog.d(TAG, "onWakeUpStarted");
+        }
+
+        synchronized (mLock) {
+            if (mActualPowerState != POWER_STATE_AWAKE) {
+                mActualPowerState = POWER_STATE_AWAKE;
+                updatePendingBroadcastLocked();
+            }
+        }
+    }
+
+    /**
+     * Called when the device has finished waking up from sleep
+     * and the display has been turned on.
+     */
+    public void onWakeUpFinished() {
+        if (DEBUG) {
+            Slog.d(TAG, "onWakeUpFinished");
+        }
+    }
+
+    /**
+     * Called when the device is going to sleep.
+     */
+    public void onGoToSleepStarted(int reason) {
+        if (DEBUG) {
+            Slog.d(TAG, "onGoToSleepStarted");
+        }
+
+        synchronized (mLock) {
+            mLastGoToSleepReason = reason;
+        }
+    }
+
+    /**
+     * Called when the device has finished going to sleep and the
+     * display has been turned off.
+     *
+     * This is a good time to make transitions that we don't want the user to see,
+     * such as bringing the key guard to focus.  There's no guarantee for this,
+     * however because the user could turn the device on again at any time.
+     * Some things may need to be protected by other mechanisms that defer screen on.
+     */
+    public void onGoToSleepFinished() {
+        if (DEBUG) {
+            Slog.d(TAG, "onGoToSleepFinished");
+        }
+
+        synchronized (mLock) {
+            if (mActualPowerState != POWER_STATE_ASLEEP) {
+                mActualPowerState = POWER_STATE_ASLEEP;
+                if (mUserActivityPending) {
+                    mUserActivityPending = false;
+                    mHandler.removeMessages(MSG_USER_ACTIVITY);
+                }
+                updatePendingBroadcastLocked();
+            }
+        }
+    }
+
+    /**
+     * Called when there has been user activity.
+     */
+    public void onUserActivity(int event, int uid) {
+        if (DEBUG) {
+            Slog.d(TAG, "onUserActivity: event=" + event + ", uid=" + uid);
+        }
+
+        try {
+            mBatteryStats.noteUserActivity(uid, event);
+        } catch (RemoteException ex) {
+            // Ignore
+        }
+
+        synchronized (mLock) {
+            if (!mUserActivityPending) {
+                mUserActivityPending = true;
+                Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY);
+                msg.setAsynchronous(true);
+                mHandler.sendMessage(msg);
+            }
+        }
+    }
+
+    private void updatePendingBroadcastLocked() {
+        if (!mBroadcastInProgress
+                && mActualPowerState != POWER_STATE_UNKNOWN
+                && mActualPowerState != mBroadcastedPowerState) {
+            mBroadcastInProgress = true;
+            mSuspendBlocker.acquire();
+            Message msg = mHandler.obtainMessage(MSG_BROADCAST);
+            msg.setAsynchronous(true);
+            mHandler.sendMessage(msg);
+        }
+    }
+
+    private void sendUserActivity() {
+        synchronized (mLock) {
+            if (!mUserActivityPending) {
+                return;
+            }
+            mUserActivityPending = false;
+        }
+
+        mPolicy.userActivity();
+    }
+
+    private void sendNextBroadcast() {
+        final int powerState;
+        final int goToSleepReason;
+        synchronized (mLock) {
+            if (mActualPowerState == POWER_STATE_UNKNOWN
+                    || mActualPowerState == mBroadcastedPowerState) {
+                mBroadcastInProgress = false;
+                mSuspendBlocker.release();
+                return;
+            }
+
+            powerState = mActualPowerState;
+            goToSleepReason = mLastGoToSleepReason;
+
+            mBroadcastedPowerState = powerState;
+            mBroadcastStartTime = SystemClock.uptimeMillis();
+        }
+
+        EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, 1);
+
+        if (powerState == POWER_STATE_AWAKE) {
+            sendWakeUpBroadcast();
+        } else {
+            sendGoToSleepBroadcast(goToSleepReason);
+        }
+    }
+
+    private void sendWakeUpBroadcast() {
+        if (DEBUG) {
+            Slog.d(TAG, "Sending wake up broadcast.");
+        }
+
+        EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, 0, 0, 0);
+
+        mPolicy.screenTurningOn(mScreenOnListener);
+        try {
+            ActivityManagerNative.getDefault().wakingUp();
+        } catch (RemoteException e) {
+            // ignore it
+        }
+
+        if (ActivityManagerNative.isSystemReady()) {
+            mContext.sendOrderedBroadcast(mScreenOnIntent, null,
+                    mWakeUpBroadcastDone, mHandler, 0, null, null);
+        } else {
+            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
+            sendNextBroadcast();
+        }
+    }
+
+    private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
+                    SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
+            sendNextBroadcast();
+        }
+    };
+
+    private void sendGoToSleepBroadcast(int reason) {
+        if (DEBUG) {
+            Slog.d(TAG, "Sending go to sleep broadcast.");
+        }
+
+        int why = WindowManagerPolicy.OFF_BECAUSE_OF_USER;
+        switch (reason) {
+            case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
+                why = WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN;
+                break;
+            case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
+                why = WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
+                break;
+        }
+
+        EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, why, 0, 0);
+
+        mPolicy.screenTurnedOff(why);
+        try {
+            ActivityManagerNative.getDefault().goingToSleep();
+        } catch (RemoteException e) {
+            // ignore it.
+        }
+
+        if (ActivityManagerNative.isSystemReady()) {
+            mContext.sendOrderedBroadcast(mScreenOffIntent, null,
+                    mGoToSleepBroadcastDone, mHandler, 0, null, null);
+        } else {
+            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
+            sendNextBroadcast();
+        }
+    }
+
+    private final BroadcastReceiver mGoToSleepBroadcastDone = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
+                    SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
+            sendNextBroadcast();
+        }
+    };
+
+    private final class NotifierHandler extends Handler {
+        public NotifierHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_USER_ACTIVITY:
+                    sendUserActivity();
+                    break;
+
+                case MSG_BROADCAST:
+                    sendNextBroadcast();
+                    break;
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/power/PhotonicModulator.java b/services/java/com/android/server/power/PhotonicModulator.java
new file mode 100644
index 0000000..f7c9c7d
--- /dev/null
+++ b/services/java/com/android/server/power/PhotonicModulator.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import com.android.server.LightsService;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Sets the value of a light asynchronously.
+ *
+ * This is done to avoid blocking the looper on devices for which
+ * setting the backlight brightness is especially slow.
+ */
+final class PhotonicModulator {
+    private static final int UNKNOWN_LIGHT_VALUE = -1;
+
+    private final Object mLock = new Object();
+
+    private final LightsService.Light mLight;
+    private final Executor mExecutor;
+    private final SuspendBlocker mSuspendBlocker;
+
+    private boolean mPendingChange;
+    private int mPendingLightValue;
+    private int mActualLightValue;
+
+    public PhotonicModulator(Executor executor, LightsService.Light light,
+            SuspendBlocker suspendBlocker) {
+        mExecutor = executor;
+        mLight = light;
+        mSuspendBlocker = suspendBlocker;
+        mPendingLightValue = UNKNOWN_LIGHT_VALUE;
+        mActualLightValue = UNKNOWN_LIGHT_VALUE;
+    }
+
+    /**
+     * Asynchronously sets the backlight brightness.
+     *
+     * @param lightValue The new light value, from 0 to 255.
+     */
+    public void setBrightness(int lightValue) {
+        synchronized (mLock) {
+            if (lightValue != mPendingLightValue) {
+                mPendingLightValue = lightValue;
+                if (!mPendingChange) {
+                    mPendingChange = true;
+                    mSuspendBlocker.acquire();
+                    mExecutor.execute(mTask);
+                }
+            }
+        }
+    }
+
+    private final Runnable mTask = new Runnable() {
+        @Override
+        public void run() {
+            for (;;) {
+                final int newLightValue;
+                synchronized (mLock) {
+                    newLightValue = mPendingLightValue;
+                    if (newLightValue == mActualLightValue) {
+                        mSuspendBlocker.release();
+                        mPendingChange = false;
+                        return;
+                    }
+                    mActualLightValue = newLightValue;
+                }
+                mLight.setBrightness(newLightValue);
+            }
+        }
+    };
+}
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 2630239..d3a3ffb 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -20,2768 +20,1470 @@
 import com.android.server.BatteryService;
 import com.android.server.EventLogTags;
 import com.android.server.LightsService;
+import com.android.server.TwilightService;
 import com.android.server.Watchdog;
-import com.android.server.am.BatteryStatsService;
+import com.android.server.am.ActivityManagerService;
 import com.android.server.display.DisplayManagerService;
 
-import android.app.ActivityManagerNative;
-import android.app.IActivityManager;
+import android.Manifest;
 import android.content.BroadcastReceiver;
-import android.content.ContentQueryMap;
 import android.content.ContentResolver;
-import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.database.ContentObserver;
-import android.database.Cursor;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.hardware.SystemSensorManager;
+import android.net.Uri;
 import android.os.BatteryManager;
-import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.IPowerManager;
-import android.os.LocalPowerManager;
+import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
-import android.os.SystemProperties;
 import android.os.WorkSource;
 import android.provider.Settings;
+import android.service.dreams.IDreamManager;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
+import android.util.TimeUtils;
 import android.view.WindowManagerPolicy;
-import static android.view.WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR;
-import static android.provider.Settings.System.DIM_SCREEN;
-import static android.provider.Settings.System.SCREEN_BRIGHTNESS;
-import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE;
-import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
-import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-import static android.provider.Settings.System.STAY_ON_WHILE_PLUGGED_IN;
-import static android.provider.Settings.System.WINDOW_ANIMATION_SCALE;
-import static android.provider.Settings.System.TRANSITION_ANIMATION_SCALE;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Observable;
-import java.util.Observer;
 
-public class PowerManagerService extends IPowerManager.Stub
-        implements LocalPowerManager, Watchdog.Monitor {
-    private static final int NOMINAL_FRAME_TIME_MS = 1000/60;
+import libcore.util.Objects;
 
+/**
+ * The power manager service is responsible for coordinating power management
+ * functions on the device.
+ */
+public final class PowerManagerService extends IPowerManager.Stub
+        implements Watchdog.Monitor {
     private static final String TAG = "PowerManagerService";
-    static final String PARTIAL_NAME = "PowerManagerService";
 
-    // could be either static or controllable at runtime
     private static final boolean DEBUG = false;
-    private static final boolean DEBUG_PROXIMITY_SENSOR = (false || DEBUG);
-    private static final boolean DEBUG_LIGHT_SENSOR = (false || DEBUG);
-    private static final boolean DEBUG_LIGHT_ANIMATION = (false || DEBUG);
-    private static final boolean DEBUG_SCREEN_ON = false;
+    private static final boolean DEBUG_SPEW = DEBUG && true;
 
-    // Wake lock that ensures that the CPU is running.  The screen might not be on.
-    private static final int PARTIAL_WAKE_LOCK_ID = 1;
+    // Message: Sent when a user activity timeout occurs to update the power state.
+    private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
+    // Message: Sent when the device enters or exits a napping or dreaming state.
+    private static final int MSG_SANDMAN = 2;
 
-    // Wake lock that ensures that the screen is on.
-    private static final int FULL_WAKE_LOCK_ID = 2;
+    // Dirty bit: mWakeLocks changed
+    private static final int DIRTY_WAKE_LOCKS = 1 << 0;
+    // Dirty bit: mWakefulness changed
+    private static final int DIRTY_WAKEFULNESS = 1 << 1;
+    // Dirty bit: user activity was poked or may have timed out
+    private static final int DIRTY_USER_ACTIVITY = 1 << 2;
+    // Dirty bit: actual display power state was updated asynchronously
+    private static final int DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED = 1 << 3;
+    // Dirty bit: mBootCompleted changed
+    private static final int DIRTY_BOOT_COMPLETED = 1 << 4;
+    // Dirty bit: settings changed
+    private static final int DIRTY_SETTINGS = 1 << 5;
+    // Dirty bit: mIsPowered changed
+    private static final int DIRTY_IS_POWERED = 1 << 6;
+    // Dirty bit: mStayOn changed
+    private static final int DIRTY_STAY_ON = 1 << 7;
+    // Dirty bit: battery state changed
+    private static final int DIRTY_BATTERY_STATE = 1 << 8;
 
-    private static final boolean LOG_PARTIAL_WL = false;
+    // Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
+    // The screen should be off or in the process of being turned off by the display controller.
+    private static final int WAKEFULNESS_ASLEEP = 0;
+    // Wakefulness: The device is fully awake.  It can be put to sleep by a call to goToSleep().
+    // When the user activity timeout expires, the device may start napping.
+    private static final int WAKEFULNESS_AWAKE = 1;
+    // Wakefulness: The device is napping.  It is deciding whether to dream or go to sleep
+    // but hasn't gotten around to it yet.  It can be awoken by a call to wakeUp(), which
+    // ends the nap. User activity may brighten the screen but does not end the nap.
+    private static final int WAKEFULNESS_NAPPING = 2;
+    // Wakefulness: The device is dreaming.  It can be awoken by a call to wakeUp(),
+    // which ends the dream.  The device goes to sleep when goToSleep() is called, when
+    // the dream ends or when unplugged.
+    // User activity may brighten the screen but does not end the dream.
+    private static final int WAKEFULNESS_DREAMING = 3;
 
-    private static final int LOCK_MASK = PowerManager.PARTIAL_WAKE_LOCK
-                                        | PowerManager.SCREEN_DIM_WAKE_LOCK
-                                        | PowerManager.SCREEN_BRIGHT_WAKE_LOCK
-                                        | PowerManager.FULL_WAKE_LOCK
-                                        | PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
+    // Summarizes the state of all active wakelocks.
+    private static final int WAKE_LOCK_CPU = 1 << 0;
+    private static final int WAKE_LOCK_SCREEN_BRIGHT = 1 << 1;
+    private static final int WAKE_LOCK_SCREEN_DIM = 1 << 2;
+    private static final int WAKE_LOCK_BUTTON_BRIGHT = 1 << 3;
+    private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4;
 
-    //                       time since last state:               time since last event:
-    // The short keylight delay comes from secure settings; this is the default.
-    private static final int SHORT_KEYLIGHT_DELAY_DEFAULT = 6000; // t+6 sec
-    private static final int MEDIUM_KEYLIGHT_DELAY = 15000;       // t+15 sec
-    private static final int LONG_KEYLIGHT_DELAY = 6000;        // t+6 sec
-    private static final int LONG_DIM_TIME = 7000;              // t+N-5 sec
+    // Summarizes the user activity state.
+    private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
+    private static final int USER_ACTIVITY_SCREEN_DIM = 1 << 1;
 
-    // How long to wait to debounce light sensor changes in milliseconds
-    private static final int LIGHT_SENSOR_DELAY = 2000;
+    // Default and minimum screen off timeout in milliseconds.
+    private static final int DEFAULT_SCREEN_OFF_TIMEOUT = 15 * 1000;
+    private static final int MINIMUM_SCREEN_OFF_TIMEOUT = 10 * 1000;
 
-    // light sensor events rate in microseconds
-    private static final int LIGHT_SENSOR_RATE = 1000000;
+    // The screen dim duration, in seconds.
+    // This is subtracted from the end of the screen off timeout so the
+    // minimum screen off timeout should be longer than this.
+    private static final int SCREEN_DIM_DURATION = 7 * 1000;
 
-    // Expansion of range of light values when applying scale from light
-    // sensor brightness setting, in the [0..255] brightness range.
-    private static final int LIGHT_SENSOR_RANGE_EXPANSION = 20;
-
-    // Scaling factor of the light sensor brightness setting when applying
-    // it to the final brightness.
-    private static final int LIGHT_SENSOR_OFFSET_SCALE = 8;
-
-    // For debouncing the proximity sensor in milliseconds
-    private static final int PROXIMITY_SENSOR_DELAY = 1000;
-
-    // trigger proximity if distance is less than 5 cm
-    private static final float PROXIMITY_THRESHOLD = 5.0f;
-
-    // Cached secure settings; see updateSettingsValues()
-    private int mShortKeylightDelay = SHORT_KEYLIGHT_DELAY_DEFAULT;
-
-    // Default timeout for screen off, if not found in settings database = 15 seconds.
-    private static final int DEFAULT_SCREEN_OFF_TIMEOUT = 15000;
-
-    // Screen brightness should always have a value, but just in case...
-    private static final int DEFAULT_SCREEN_BRIGHTNESS = 192;
-
-    // Threshold for BRIGHTNESS_LOW_BATTERY (percentage)
-    // Screen will stay dim if battery level is <= LOW_BATTERY_THRESHOLD
-    private static final int LOW_BATTERY_THRESHOLD = 10;
-
-    // flags for setPowerState
-    private static final int ALL_LIGHTS_OFF         = 0x00000000;
-    private static final int SCREEN_ON_BIT          = 0x00000001;
-    private static final int SCREEN_BRIGHT_BIT      = 0x00000002;
-    private static final int BUTTON_BRIGHT_BIT      = 0x00000004;
-    private static final int KEYBOARD_BRIGHT_BIT    = 0x00000008;
-    private static final int BATTERY_LOW_BIT        = 0x00000010;
-
-    // values for setPowerState
-
-    // SCREEN_OFF == everything off
-    private static final int SCREEN_OFF         = 0x00000000;
-
-    // SCREEN_DIM == screen on, screen backlight dim
-    private static final int SCREEN_DIM         = SCREEN_ON_BIT;
-
-    // SCREEN_BRIGHT == screen on, screen backlight bright
-    private static final int SCREEN_BRIGHT      = SCREEN_ON_BIT | SCREEN_BRIGHT_BIT;
-
-    // SCREEN_BUTTON_BRIGHT == screen on, screen and button backlights bright
-    private static final int SCREEN_BUTTON_BRIGHT  = SCREEN_BRIGHT | BUTTON_BRIGHT_BIT;
-
-    // SCREEN_BUTTON_BRIGHT == screen on, screen, button and keyboard backlights bright
-    private static final int ALL_BRIGHT         = SCREEN_BUTTON_BRIGHT | KEYBOARD_BRIGHT_BIT;
-
-    // used for noChangeLights in setPowerState()
-    private static final int LIGHTS_MASK        = SCREEN_BRIGHT_BIT | BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT;
-
-    // animate screen lights in PowerManager (as opposed to SurfaceFlinger)
-    boolean mAnimateScreenLights = true;
-
-    static final int ANIM_STEPS = 60; // nominal # of frames at 60Hz
-    // Slower animation for autobrightness changes
-    static final int AUTOBRIGHTNESS_ANIM_STEPS = 2 * ANIM_STEPS;
-    // Even slower animation for autodimness changes. Set to max to effectively disable dimming.
-    // Note 100 is used to keep the mWindowScaleAnimation scaling below from overflowing an int.
-    static final int AUTODIMNESS_ANIM_STEPS = Integer.MAX_VALUE / (NOMINAL_FRAME_TIME_MS * 100);
-    // Number of steps when performing a more immediate brightness change.
-    static final int IMMEDIATE_ANIM_STEPS = 4;
-
-    // These magic numbers are the initial state of the LEDs at boot.  Ideally
-    // we should read them from the driver, but our current hardware returns 0
-    // for the initial value.  Oops!
-    static final int INITIAL_SCREEN_BRIGHTNESS = 255;
-    static final int INITIAL_BUTTON_BRIGHTNESS = PowerManager.BRIGHTNESS_OFF;
-    static final int INITIAL_KEYBOARD_BRIGHTNESS = PowerManager.BRIGHTNESS_OFF;
-
-    private final int MY_UID;
-    private final int MY_PID;
-
-    private boolean mDoneBooting = false;
-    private boolean mBootCompleted = false;
-    private boolean mHeadless = false;
-    private int mStayOnConditions = 0;
-    private final int[] mBroadcastQueue = new int[] { -1, -1, -1 };
-    private final int[] mBroadcastWhy = new int[3];
-    private boolean mPreparingForScreenOn = false;
-    private boolean mSkippedScreenOn = false;
-    private boolean mInitialized = false;
-    private int mPartialCount = 0;
-    private int mPowerState;
-    // mScreenOffReason can be WindowManagerPolicy.OFF_BECAUSE_OF_USER,
-    // WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT or WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR
-    private int mScreenOffReason;
-    private int mUserState;
-    private boolean mKeyboardVisible = false;
-    private boolean mUserActivityAllowed = true;
-    private int mProximityWakeLockCount = 0;
-    private boolean mProximitySensorEnabled = false;
-    private boolean mProximitySensorActive = false;
-    private int mProximityPendingValue = -1; // -1 == nothing, 0 == inactive, 1 == active
-    private long mLastProximityEventTime;
-    private int mScreenOffTimeoutSetting;
-    private int mMaximumScreenOffTimeout = Integer.MAX_VALUE;
-    private int mKeylightDelay;
-    private int mDimDelay;
-    private int mScreenOffDelay;
-    private int mWakeLockState;
-    private long mLastEventTime = 0;
-    private long mScreenOffTime;
-    private volatile WindowManagerPolicy mPolicy;
-    private final LockList mLocks = new LockList();
-    private Intent mScreenOffIntent;
-    private Intent mScreenOnIntent;
-    private LightsService mLightsService;
     private Context mContext;
-    private LightsService.Light mLcdLight;
-    private LightsService.Light mButtonLight;
-    private LightsService.Light mKeyboardLight;
-    private LightsService.Light mAttentionLight;
-    private UnsynchronizedWakeLock mBroadcastWakeLock;
-    private UnsynchronizedWakeLock mStayOnWhilePluggedInScreenDimLock;
-    private UnsynchronizedWakeLock mStayOnWhilePluggedInPartialLock;
-    private UnsynchronizedWakeLock mPreventScreenOnPartialLock;
-    private UnsynchronizedWakeLock mProximityPartialLock;
-    private HandlerThread mHandlerThread;
-    private Handler mScreenOffHandler;
-    private Handler mScreenBrightnessHandler;
-    private Handler mHandler;
-    private final TimeoutTask mTimeoutTask = new TimeoutTask();
-    private ScreenBrightnessAnimator mScreenBrightnessAnimator;
-    private boolean mWaitingForFirstLightSensor = false;
-    private boolean mStillNeedSleepNotification;
-    private boolean mIsPowered = false;
-    private IActivityManager mActivityService;
-    private IBatteryStats mBatteryStats;
+    private LightsService mLightsService;
     private BatteryService mBatteryService;
-    private DisplayManagerService mDisplayManagerService;
-    private SensorManager mSensorManager;
-    private Sensor mProximitySensor;
-    private Sensor mLightSensor;
-    private boolean mLightSensorEnabled;
-    private float mLightSensorValue = -1;
-    private boolean mProxIgnoredBecauseScreenTurnedOff = false;
-    private int mHighestLightSensorValue = -1;
-    private boolean mLightSensorPendingDecrease = false;
-    private boolean mLightSensorPendingIncrease = false;
-    private float mLightSensorPendingValue = -1;
-    private float mLightSensorAdjustSetting = 0;
-    private int mLightSensorScreenBrightness = -1;
-    private int mLightSensorButtonBrightness = -1;
-    private int mLightSensorKeyboardBrightness = -1;
-    private boolean mDimScreen = true;
-    private boolean mIsDocked = false;
-    private long mNextTimeout;
-    private volatile int mPokey = 0;
-    private volatile boolean mPokeAwakeOnSet = false;
-    private volatile boolean mInitComplete = false;
-    private final HashMap<IBinder,PokeLock> mPokeLocks = new HashMap<IBinder,PokeLock>();
-    // mLastScreenOnTime is the time the screen was last turned on
-    private long mLastScreenOnTime;
-    private boolean mPreventScreenOn;
-    private int mScreenBrightnessSetting = DEFAULT_SCREEN_BRIGHTNESS;
-    private int mScreenBrightnessOverride = -1;
-    private int mButtonBrightnessOverride = -1;
-    private int mScreenBrightnessDim;
-    private boolean mUseSoftwareAutoBrightness;
-    private boolean mAutoBrightessEnabled;
-    private int[] mAutoBrightnessLevels;
-    private int[] mLcdBacklightValues;
-    private int[] mButtonBacklightValues;
-    private int[] mKeyboardBacklightValues;
-    private int mLightSensorWarmupTime;
-    boolean mUnplugTurnsOnScreen;
-    private int mWarningSpewThrottleCount;
-    private long mWarningSpewThrottleTime;
-    private int mAnimationSetting = ANIM_SETTING_OFF;
-    private float mWindowScaleAnimation;
+    private IBatteryStats mBatteryStats;
+    private HandlerThread mHandlerThread;
+    private PowerManagerHandler mHandler;
+    private WindowManagerPolicy mPolicy;
+    private Notifier mNotifier;
+    private DisplayPowerController mDisplayPowerController;
+    private SettingsObserver mSettingsObserver;
+    private IDreamManager mDreamManager;
+    private LightsService.Light mAttentionLight;
 
-    // Must match with the ISurfaceComposer constants in C++.
-    private static final int ANIM_SETTING_ON = 0x01;
-    private static final int ANIM_SETTING_OFF = 0x10;
+    private final Object mLock = new Object();
+
+    // A bitfield that indicates what parts of the power state have
+    // changed and need to be recalculated.
+    private int mDirty;
+
+    // Indicates whether the device is awake or asleep or somewhere in between.
+    // This is distinct from the screen power state, which is managed separately.
+    private int mWakefulness;
+
+    // True if MSG_SANDMAN has been scheduled.
+    private boolean mSandmanScheduled;
+
+    // Table of all suspend blockers.
+    // There should only be a few of these.
+    private final ArrayList<SuspendBlocker> mSuspendBlockers = new ArrayList<SuspendBlocker>();
+
+    // Table of all wake locks acquired by applications.
+    private final ArrayList<WakeLock> mWakeLocks = new ArrayList<WakeLock>();
+
+    // A bitfield that summarizes the state of all active wakelocks.
+    private int mWakeLockSummary;
+
+    // If true, instructs the display controller to wait for the proximity sensor to
+    // go negative before turning the screen on.
+    private boolean mRequestWaitForNegativeProximity;
+
+    // Timestamp of the last time the device was awoken or put to sleep.
+    private long mLastWakeTime;
+    private long mLastSleepTime;
+
+    // True if we need to send a wake up or go to sleep finished notification
+    // when the display is ready.
+    private boolean mSendWakeUpFinishedNotificationWhenReady;
+    private boolean mSendGoToSleepFinishedNotificationWhenReady;
+
+    // Timestamp of the last call to user activity.
+    private long mLastUserActivityTime;
+    private long mLastUserActivityTimeNoChangeLights;
+
+    // A bitfield that summarizes the effect of the user activity timer.
+    // A zero value indicates that the user activity timer has expired.
+    private int mUserActivitySummary;
+
+    // The desired display power state.  The actual state may lag behind the
+    // requested because it is updated asynchronously by the display power controller.
+    private final DisplayPowerRequest mDisplayPowerRequest = new DisplayPowerRequest();
+
+    // The time the screen was last turned off, in elapsedRealtime() timebase.
+    private long mLastScreenOffEventElapsedRealTime;
+
+    // True if the display power state has been fully applied, which means the display
+    // is actually on or actually off or whatever was requested.
+    private boolean mDisplayReady;
+
+    // True if holding a wake-lock to block suspend of the CPU.
+    private boolean mHoldingWakeLockSuspendBlocker;
+
+    // The suspend blocker used to keep the CPU alive when wake locks have been acquired.
+    private final SuspendBlocker mWakeLockSuspendBlocker;
+
+    // True if systemReady() has been called.
+    private boolean mSystemReady;
+
+    // True if boot completed occurred.  We keep the screen on until this happens.
+    private boolean mBootCompleted;
+
+    // True if the device is plugged into a power source.
+    private boolean mIsPowered;
+
+    // True if the device should wake up when plugged or unplugged.
+    private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
+
+    // True if dreams are supported on this device.
+    private boolean mDreamsSupportedConfig;
+
+    // True if dreams are enabled by the user.
+    private boolean mDreamsEnabledSetting;
+
+    // The screen off timeout setting value in milliseconds.
+    private int mScreenOffTimeoutSetting;
+
+    // The maximum allowable screen off timeout according to the device
+    // administration policy.  Overrides other settings.
+    private int mMaximumScreenOffTimeoutFromDeviceAdmin = Integer.MAX_VALUE;
+
+    // The stay on while plugged in setting.
+    // A bitfield of battery conditions under which to make the screen stay on.
+    private int mStayOnWhilePluggedInSetting;
+
+    // True if the device should stay on.
+    private boolean mStayOn;
+
+    // Screen brightness setting limits.
+    private int mScreenBrightnessSettingMinimum;
+    private int mScreenBrightnessSettingMaximum;
+    private int mScreenBrightnessSettingDefault;
+
+    // The screen brightness setting, from 0 to 255.
+    // Use -1 if no value has been set.
+    private int mScreenBrightnessSetting;
+
+    // The screen auto-brightness adjustment setting, from -1 to 1.
+    // Use 0 if there is no adjustment.
+    private float mScreenAutoBrightnessAdjustmentSetting;
+
+    // The screen brightness mode.
+    // One of the Settings.System.SCREEN_BRIGHTNESS_MODE_* constants.
+    private int mScreenBrightnessModeSetting;
+
+    // The screen brightness setting override from the window manager
+    // to allow the current foreground activity to override the brightness.
+    // Use -1 to disable.
+    private int mScreenBrightnessOverrideFromWindowManager = -1;
+
+    // The screen brightness setting override from the settings application
+    // to temporarily adjust the brightness until next updated,
+    // Use -1 to disable.
+    private int mTemporaryScreenBrightnessSettingOverride = -1;
+
+    // The screen brightness adjustment setting override from the settings
+    // application to temporarily adjust the auto-brightness adjustment factor
+    // until next updated, in the range -1..1.
+    // Use NaN to disable.
+    private float mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = Float.NaN;
 
     private native void nativeInit();
-    private native void nativeSetPowerState(boolean screenOn, boolean screenBright);
-    private native void nativeStartSurfaceFlingerAnimation(int mode);
-    private static native void nativeAcquireWakeLock(int lock, String id);
-    private static native void nativeReleaseWakeLock(String id);
-    private static native int nativeSetScreenState(boolean on);
     private static native void nativeShutdown();
     private static native void nativeReboot(String reason) throws IOException;
 
-    /*
-    static PrintStream mLog;
-    static {
-        try {
-            mLog = new PrintStream("/data/power.log");
-        }
-        catch (FileNotFoundException e) {
-            android.util.Slog.e(TAG, "Life is hard", e);
-        }
-    }
-    static class Log {
-        static void d(String tag, String s) {
-            mLog.println(s);
-            android.util.Slog.d(tag, s);
-        }
-        static void i(String tag, String s) {
-            mLog.println(s);
-            android.util.Slog.i(tag, s);
-        }
-        static void w(String tag, String s) {
-            mLog.println(s);
-            android.util.Slog.w(tag, s);
-        }
-        static void e(String tag, String s) {
-            mLog.println(s);
-            android.util.Slog.e(tag, s);
-        }
-    }
-    */
+    private static native void nativeSetPowerState(boolean screenOn, boolean screenBright);
+    private static native void nativeAcquireSuspendBlocker(String name);
+    private static native void nativeReleaseSuspendBlocker(String name);
 
-    /**
-     * This class works around a deadlock between the lock in PowerManager.WakeLock
-     * and our synchronizing on mLocks.  PowerManager.WakeLock synchronizes on its
-     * mToken object so it can be accessed from any thread, but it calls into here
-     * with its lock held.  This class is essentially a reimplementation of
-     * PowerManager.WakeLock, but without that extra synchronized block, because we'll
-     * only call it with our own locks held.
-     */
-    private class UnsynchronizedWakeLock {
-        int mFlags;
-        String mTag;
-        IBinder mToken;
-        int mCount = 0;
-        boolean mRefCounted;
-        boolean mHeld;
-
-        UnsynchronizedWakeLock(int flags, String tag, boolean refCounted) {
-            mFlags = flags;
-            mTag = tag;
-            mToken = new Binder();
-            mRefCounted = refCounted;
-        }
-
-        public void acquire() {
-            if (!mRefCounted || mCount++ == 0) {
-                long ident = Binder.clearCallingIdentity();
-                try {
-                    PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken,
-                            MY_UID, MY_PID, mTag, null);
-                    mHeld = true;
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-            }
-        }
-
-        public void release() {
-            if (!mRefCounted || --mCount == 0) {
-                PowerManagerService.this.releaseWakeLockLocked(mToken, 0, false);
-                mHeld = false;
-            }
-            if (mCount < 0) {
-                throw new RuntimeException("WakeLock under-locked " + mTag);
-            }
-        }
-
-        public boolean isHeld()
-        {
-            return mHeld;
-        }
-
-        public String toString() {
-            return "UnsynchronizedWakeLock(mFlags=0x" + Integer.toHexString(mFlags)
-                    + " mCount=" + mCount + " mHeld=" + mHeld + ")";
-        }
-    }
-
-    private final class BatteryReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            synchronized (mLocks) {
-                boolean wasPowered = mIsPowered;
-                mIsPowered = mBatteryService.isPowered();
-
-                if (mIsPowered != wasPowered) {
-                    // update mStayOnWhilePluggedIn wake lock
-                    updateWakeLockLocked();
-
-                    // treat plugging and unplugging the devices as a user activity.
-                    // users find it disconcerting when they unplug the device
-                    // and it shuts off right away.
-                    // to avoid turning on the screen when unplugging, we only trigger
-                    // user activity when screen was already on.
-                    // temporarily set mUserActivityAllowed to true so this will work
-                    // even when the keyguard is on.
-                    // However, you can also set config_unplugTurnsOnScreen to have it
-                    // turn on.  Some devices want this because they don't have a
-                    // charging LED.
-                    synchronized (mLocks) {
-                        if (!wasPowered || (mPowerState & SCREEN_ON_BIT) != 0 ||
-                                mUnplugTurnsOnScreen) {
-                            forceUserActivityLocked();
-                        }
-                    }
-
-                    // stop the screensaver if we're now unplugged
-                    if (mPolicy != null && wasPowered) {
-                        mPolicy.stopScreenSaver();
-                    }
-                }
-            }
-        }
-    }
-
-    private final class BootCompletedReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            bootCompleted();
-        }
-    }
-
-    private final class DockReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
-                    Intent.EXTRA_DOCK_STATE_UNDOCKED);
-            dockStateChanged(state);
-        }
-    }
-
-    /**
-     * Set the setting that determines whether the device stays on when plugged in.
-     * The argument is a bit string, with each bit specifying a power source that,
-     * when the device is connected to that source, causes the device to stay on.
-     * See {@link android.os.BatteryManager} for the list of power sources that
-     * can be specified. Current values include {@link android.os.BatteryManager#BATTERY_PLUGGED_AC}
-     * and {@link android.os.BatteryManager#BATTERY_PLUGGED_USB}
-     * @param val an {@code int} containing the bits that specify which power sources
-     * should cause the device to stay on.
-     */
-    public void setStayOnSetting(int val) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS, null);
-        Settings.System.putInt(mContext.getContentResolver(),
-                Settings.System.STAY_ON_WHILE_PLUGGED_IN, val);
-    }
-
-    public void setMaximumScreenOffTimeount(int timeMs) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.WRITE_SECURE_SETTINGS, null);
-        synchronized (mLocks) {
-            mMaximumScreenOffTimeout = timeMs;
-            // recalculate everything
-            setScreenOffTimeoutsLocked();
-        }
-    }
-
-    int getStayOnConditionsLocked() {
-        return mMaximumScreenOffTimeout <= 0 || mMaximumScreenOffTimeout == Integer.MAX_VALUE
-                ? mStayOnConditions : 0;
-    }
-
-    private class SettingsObserver implements Observer {
-        private int getInt(String name, int defValue) {
-            ContentValues values = mSettings.getValues(name);
-            Integer iVal = values != null ? values.getAsInteger(Settings.System.VALUE) : null;
-            return iVal != null ? iVal : defValue;
-        }
-
-        private float getFloat(String name, float defValue) {
-            ContentValues values = mSettings.getValues(name);
-            Float fVal = values != null ? values.getAsFloat(Settings.System.VALUE) : null;
-            return fVal != null ? fVal : defValue;
-        }
-
-        public void update(Observable o, Object arg) {
-            synchronized (mLocks) {
-                // STAY_ON_WHILE_PLUGGED_IN, default to when plugged into AC
-                mStayOnConditions = getInt(STAY_ON_WHILE_PLUGGED_IN,
-                        BatteryManager.BATTERY_PLUGGED_AC);
-                updateWakeLockLocked();
-
-                // SCREEN_OFF_TIMEOUT, default to 15 seconds
-                mScreenOffTimeoutSetting = getInt(SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT);
-
-                // DIM_SCREEN
-                //mDimScreen = getInt(DIM_SCREEN) != 0;
-
-                mScreenBrightnessSetting = getInt(SCREEN_BRIGHTNESS, DEFAULT_SCREEN_BRIGHTNESS);
-                mLightSensorAdjustSetting = 0; //getFloat(SCREEN_AUTO_BRIGHTNESS_ADJ, 0);
-
-                // SCREEN_BRIGHTNESS_MODE, default to manual
-                setScreenBrightnessMode(getInt(SCREEN_BRIGHTNESS_MODE,
-                        Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL));
-
-                // recalculate everything
-                setScreenOffTimeoutsLocked();
-
-                mWindowScaleAnimation = getFloat(WINDOW_ANIMATION_SCALE, 1.0f);
-                final float transitionScale = getFloat(TRANSITION_ANIMATION_SCALE, 1.0f);
-                mAnimationSetting = 0;
-                if (mWindowScaleAnimation > 0.5f) {
-                    mAnimationSetting |= ANIM_SETTING_OFF;
-                }
-                if (transitionScale > 0.5f) {
-                    // Uncomment this if you want the screen-on animation.
-                    // mAnimationSetting |= ANIM_SETTING_ON;
-                }
-            }
-        }
-    }
+    static native void nativeSetScreenState(boolean on);
 
     public PowerManagerService() {
-        // Hack to get our uid...  should have a func for this.
-        long token = Binder.clearCallingIdentity();
-        MY_UID = Process.myUid();
-        MY_PID = Process.myPid();
-        Binder.restoreCallingIdentity(token);
-
-        // assume nothing is on yet
-        mUserState = mPowerState = 0;
-
-        // Add ourself to the Watchdog monitors.
-        Watchdog.getInstance().addMonitor(this);
+        synchronized (mLock) {
+            mWakeLockSuspendBlocker = createSuspendBlockerLocked("PowerManagerService");
+            mWakeLockSuspendBlocker.acquire();
+            mHoldingWakeLockSuspendBlocker = true;
+            mWakefulness = WAKEFULNESS_AWAKE;
+        }
 
         nativeInit();
     }
 
-    private ContentQueryMap mSettings;
-
-    public void init(Context context, LightsService lights, IActivityManager activity,
-            BatteryService battery, DisplayManagerService displayManagerService) {
-        mLightsService = lights;
+    /**
+     * Initialize the power manager.
+     * Must be called before any other functions within the power manager are called.
+     */
+    public void init(Context context, LightsService ls,
+            ActivityManagerService am, BatteryService bs, IBatteryStats bss,
+            DisplayManagerService dm) {
         mContext = context;
-        mActivityService = activity;
-        mBatteryStats = BatteryStatsService.getService();
-        mBatteryService = battery;
-        mDisplayManagerService = displayManagerService;
-
-        mLcdLight = lights.getLight(LightsService.LIGHT_ID_BACKLIGHT);
-        mButtonLight = lights.getLight(LightsService.LIGHT_ID_BUTTONS);
-        mKeyboardLight = lights.getLight(LightsService.LIGHT_ID_KEYBOARD);
-        mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);
-        mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0"));
-
-        mInitComplete = false;
-        mScreenBrightnessAnimator = new ScreenBrightnessAnimator("mScreenBrightnessUpdaterThread",
-                Process.THREAD_PRIORITY_DISPLAY);
-        mScreenBrightnessAnimator.start();
-
-        synchronized (mScreenBrightnessAnimator) {
-            while (!mInitComplete) {
-                try {
-                    mScreenBrightnessAnimator.wait();
-                } catch (InterruptedException e) {
-                    // Ignore
-                }
-            }
-        }
-
-        mInitComplete = false;
-        mHandlerThread = new HandlerThread("PowerManagerService") {
-            @Override
-            protected void onLooperPrepared() {
-                super.onLooperPrepared();
-                initInThread();
-            }
-        };
+        mLightsService = ls;
+        mBatteryService = bs;
+        mBatteryStats = bss;
+        mHandlerThread = new HandlerThread(TAG);
         mHandlerThread.start();
+        mHandler = new PowerManagerHandler(mHandlerThread.getLooper());
 
-        synchronized (mHandlerThread) {
-            while (!mInitComplete) {
-                try {
-                    mHandlerThread.wait();
-                } catch (InterruptedException e) {
-                    // Ignore
-                }
-            }
-        }
+        Watchdog.getInstance().addMonitor(this);
+    }
 
-        synchronized (mLocks) {
-            updateNativePowerStateLocked();
-            // We make sure to start out with the screen on due to user activity.
-            // (They did just boot their device, after all.)
-            forceUserActivityLocked();
-            mInitialized = true;
+    public void setPolicy(WindowManagerPolicy policy) {
+        synchronized (mLock) {
+            mPolicy = policy;
         }
     }
 
-    void initInThread() {
-        mHandler = new Handler();
+    public void systemReady(TwilightService twilight) {
+        synchronized (mLock) {
+            mSystemReady = true;
 
-        mBroadcastWakeLock = new UnsynchronizedWakeLock(
-                                PowerManager.PARTIAL_WAKE_LOCK, "sleep_broadcast", true);
-        mStayOnWhilePluggedInScreenDimLock = new UnsynchronizedWakeLock(
-                                PowerManager.SCREEN_DIM_WAKE_LOCK, "StayOnWhilePluggedIn Screen Dim", false);
-        mStayOnWhilePluggedInPartialLock = new UnsynchronizedWakeLock(
-                                PowerManager.PARTIAL_WAKE_LOCK, "StayOnWhilePluggedIn Partial", false);
-        mPreventScreenOnPartialLock = new UnsynchronizedWakeLock(
-                                PowerManager.PARTIAL_WAKE_LOCK, "PreventScreenOn Partial", false);
-        mProximityPartialLock = new UnsynchronizedWakeLock(
-                                PowerManager.PARTIAL_WAKE_LOCK, "Proximity Partial", false);
+            PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
+            mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
+            mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
+            mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
 
-        mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
-        mScreenOnIntent.addFlags(
-                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
-        mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
-        mScreenOffIntent.addFlags(
-                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
+            mNotifier = new Notifier(mHandler.getLooper(), mContext, mBatteryStats,
+                    createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
+                    mPolicy, mScreenOnListener);
+            mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
+                    mContext, mNotifier, mLightsService, twilight,
+                    createSuspendBlockerLocked("PowerManagerService.Display"),
+                    mDisplayPowerControllerCallbacks, mHandler);
 
-        Resources resources = mContext.getResources();
+            mSettingsObserver = new SettingsObserver(mHandler);
+            mAttentionLight = mLightsService.getLight(LightsService.LIGHT_ID_ATTENTION);
 
-        mAnimateScreenLights = resources.getBoolean(
-                com.android.internal.R.bool.config_animateScreenLights);
+            // Register for broadcasts from other components of the system.
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+            mContext.registerReceiver(new BatteryReceiver(), filter);
 
-        mUnplugTurnsOnScreen = resources.getBoolean(
+            filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_BOOT_COMPLETED);
+            mContext.registerReceiver(new BootCompletedReceiver(), filter);
+
+            filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_DOCK_EVENT);
+            mContext.registerReceiver(new DockReceiver(), filter);
+
+            // Register for settings changes.
+            final ContentResolver resolver = mContext.getContentResolver();
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.SCREENSAVER_ENABLED), false, mSettingsObserver);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.System.SCREEN_OFF_TIMEOUT), false, mSettingsObserver);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.System.STAY_ON_WHILE_PLUGGED_IN), false, mSettingsObserver);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.System.SCREEN_BRIGHTNESS), false, mSettingsObserver);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    Settings.System.SCREEN_BRIGHTNESS_MODE), false, mSettingsObserver);
+
+            // Go.
+            readConfigurationLocked();
+            updateSettingsLocked();
+            mDirty |= DIRTY_BATTERY_STATE;
+            updatePowerStateLocked();
+        }
+    }
+
+    private void readConfigurationLocked() {
+        final Resources resources = mContext.getResources();
+
+        mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_unplugTurnsOnScreen);
-
-        mScreenBrightnessDim = resources.getInteger(
-                com.android.internal.R.integer.config_screenBrightnessDim);
-
-        // read settings for auto-brightness
-        mUseSoftwareAutoBrightness = resources.getBoolean(
-                com.android.internal.R.bool.config_automatic_brightness_available);
-        if (mUseSoftwareAutoBrightness) {
-            mAutoBrightnessLevels = resources.getIntArray(
-                    com.android.internal.R.array.config_autoBrightnessLevels);
-            mLcdBacklightValues = resources.getIntArray(
-                    com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
-            mButtonBacklightValues = resources.getIntArray(
-                    com.android.internal.R.array.config_autoBrightnessButtonBacklightValues);
-            mKeyboardBacklightValues = resources.getIntArray(
-                    com.android.internal.R.array.config_autoBrightnessKeyboardBacklightValues);
-            mLightSensorWarmupTime = resources.getInteger(
-                    com.android.internal.R.integer.config_lightSensorWarmupTime);
-        }
-
-       ContentResolver resolver = mContext.getContentResolver();
-        Cursor settingsCursor = resolver.query(Settings.System.CONTENT_URI, null,
-                "(" + Settings.System.NAME + "=?) or ("
-                        + Settings.System.NAME + "=?) or ("
-                        + Settings.System.NAME + "=?) or ("
-                        + Settings.System.NAME + "=?) or ("
-                        + Settings.System.NAME + "=?) or ("
-                        + Settings.System.NAME + "=?) or ("
-                        + Settings.System.NAME + "=?) or ("
-                        + Settings.System.NAME + "=?)",
-                new String[]{STAY_ON_WHILE_PLUGGED_IN, SCREEN_OFF_TIMEOUT, DIM_SCREEN, SCREEN_BRIGHTNESS,
-                        SCREEN_BRIGHTNESS_MODE, /*SCREEN_AUTO_BRIGHTNESS_ADJ,*/
-                        WINDOW_ANIMATION_SCALE, TRANSITION_ANIMATION_SCALE},
-                null);
-        mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mHandler);
-        SettingsObserver settingsObserver = new SettingsObserver();
-        mSettings.addObserver(settingsObserver);
-
-        // pretend that the settings changed so we will get their initial state
-        settingsObserver.update(mSettings, null);
-
-        // register for the battery changed notifications
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-        mContext.registerReceiver(new BatteryReceiver(), filter);
-        filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
-        mContext.registerReceiver(new BootCompletedReceiver(), filter);
-        filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_DOCK_EVENT);
-        mContext.registerReceiver(new DockReceiver(), filter);
-
-        // Listen for secure settings changes
-        mContext.getContentResolver().registerContentObserver(
-            Settings.Secure.CONTENT_URI, true,
-            new ContentObserver(new Handler()) {
-                public void onChange(boolean selfChange) {
-                    updateSettingsValues();
-                }
-            });
-        updateSettingsValues();
-
-        synchronized (mHandlerThread) {
-            mInitComplete = true;
-            mHandlerThread.notifyAll();
-        }
+        mDreamsSupportedConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_enableDreams);
     }
 
-    /**
-     * Low-level function turn the device off immediately, without trying
-     * to be clean.  Most people should use
-     * {@link com.android.server.power.internal.app.ShutdownThread} for a clean shutdown.
-     */
-    public static void lowLevelShutdown() {
-        nativeShutdown();
-    }
+    private void updateSettingsLocked() {
+        final ContentResolver resolver = mContext.getContentResolver();
 
-    /**
-     * Low-level function to reboot the device.
-     *
-     * @param reason code to pass to the kernel (e.g. "recovery"), or null.
-     * @throws IOException if reboot fails for some reason (eg, lack of
-     *         permission)
-     */
-    public static void lowLevelReboot(String reason) throws IOException {
-        nativeReboot(reason);
-    }
+        mDreamsEnabledSetting = (Settings.Secure.getInt(resolver,
+                Settings.Secure.SCREENSAVER_ENABLED, 0) != 0);
+        mScreenOffTimeoutSetting = Settings.System.getInt(resolver,
+                Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT);
+        mStayOnWhilePluggedInSetting = Settings.System.getInt(resolver,
+                Settings.System.STAY_ON_WHILE_PLUGGED_IN,
+                BatteryManager.BATTERY_PLUGGED_AC);
 
-    private class WakeLock implements IBinder.DeathRecipient
-    {
-        WakeLock(int f, IBinder b, String t, int u, int p) {
-            super();
-            flags = f;
-            binder = b;
-            tag = t;
-            uid = u == MY_UID ? Process.SYSTEM_UID : u;
-            pid = p;
-            if (u != MY_UID || (
-                    !"KEEP_SCREEN_ON_FLAG".equals(tag)
-                    && !"KeyInputQueue".equals(tag))) {
-                monitorType = (f & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK
-                        ? BatteryStats.WAKE_TYPE_PARTIAL
-                        : BatteryStats.WAKE_TYPE_FULL;
-            } else {
-                monitorType = -1;
-            }
-            try {
-                b.linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                binderDied();
-            }
+        final int oldScreenBrightnessSetting = mScreenBrightnessSetting;
+        mScreenBrightnessSetting = Settings.System.getInt(resolver,
+                Settings.System.SCREEN_BRIGHTNESS, mScreenBrightnessSettingDefault);
+        if (oldScreenBrightnessSetting != mScreenBrightnessSetting) {
+            mTemporaryScreenBrightnessSettingOverride = -1;
         }
-        public void binderDied() {
-            synchronized (mLocks) {
-                releaseWakeLockLocked(this.binder, 0, true);
-            }
+
+        final float oldScreenAutoBrightnessAdjustmentSetting =
+                mScreenAutoBrightnessAdjustmentSetting;
+        mScreenAutoBrightnessAdjustmentSetting = Settings.System.getFloat(resolver,
+                Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f);
+        if (oldScreenAutoBrightnessAdjustmentSetting != mScreenAutoBrightnessAdjustmentSetting) {
+            mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = Float.NaN;
         }
-        final int flags;
-        final IBinder binder;
-        final String tag;
-        final int uid;
-        final int pid;
-        final int monitorType;
-        WorkSource ws;
-        boolean activated = true;
-        int minState;
+
+        mScreenBrightnessModeSetting = Settings.System.getInt(resolver,
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
+
+        mDirty |= DIRTY_SETTINGS;
     }
 
-    private void updateWakeLockLocked() {
-        final int stayOnConditions = getStayOnConditionsLocked();
-        if (stayOnConditions != 0 && mBatteryService.isPowered(stayOnConditions)) {
-            // keep the device on if we're plugged in and mStayOnWhilePluggedIn is set.
-            mStayOnWhilePluggedInScreenDimLock.acquire();
-            mStayOnWhilePluggedInPartialLock.acquire();
+    private void handleSettingsChangedLocked() {
+        updateSettingsLocked();
+        updatePowerStateLocked();
+    }
+
+    @Override // Binder call
+    public void acquireWakeLock(IBinder lock, int flags, String tag, WorkSource ws) {
+        if (lock == null) {
+            throw new IllegalArgumentException("lock must not be null");
+        }
+        PowerManager.validateWakeLockParameters(flags, tag);
+
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
+        if (ws != null && ws.size() != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.UPDATE_DEVICE_STATS, null);
         } else {
-            mStayOnWhilePluggedInScreenDimLock.release();
-            mStayOnWhilePluggedInPartialLock.release();
+            ws = null;
         }
-    }
 
-    private boolean isScreenLock(int flags)
-    {
-        int n = flags & LOCK_MASK;
-        return n == PowerManager.FULL_WAKE_LOCK
-                || n == PowerManager.SCREEN_BRIGHT_WAKE_LOCK
-                || n == PowerManager.SCREEN_DIM_WAKE_LOCK
-                || n == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
-    }
-
-    void enforceWakeSourcePermission(int uid, int pid) {
-        if (uid == Process.myUid()) {
-            return;
-        }
-        mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
-                pid, uid, null);
-    }
-
-    public void acquireWakeLock(int flags, IBinder lock, String tag, WorkSource ws) {
-        int uid = Binder.getCallingUid();
-        int pid = Binder.getCallingPid();
-        if (uid != Process.myUid()) {
-            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
-        }
-        if (ws != null) {
-            enforceWakeSourcePermission(uid, pid);
-        }
-        long ident = Binder.clearCallingIdentity();
+        final int uid = Binder.getCallingUid();
+        final int pid = Binder.getCallingPid();
+        final long ident = Binder.clearCallingIdentity();
         try {
-            synchronized (mLocks) {
-                acquireWakeLockLocked(flags, lock, uid, pid, tag, ws);
-            }
+            acquireWakeLockInternal(lock, flags, tag, ws, uid, pid);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
-    void noteStartWakeLocked(WakeLock wl, WorkSource ws) {
-        if (wl.monitorType >= 0) {
-            long origId = Binder.clearCallingIdentity();
-            try {
-                if (ws != null) {
-                    mBatteryStats.noteStartWakelockFromSource(ws, wl.pid, wl.tag,
-                            wl.monitorType);
-                } else {
-                    mBatteryStats.noteStartWakelock(wl.uid, wl.pid, wl.tag, wl.monitorType);
-                }
-            } catch (RemoteException e) {
-                // Ignore
-            } finally {
-                Binder.restoreCallingIdentity(origId);
+    private void acquireWakeLockInternal(IBinder lock, int flags, String tag, WorkSource ws,
+            int uid, int pid) {
+        synchronized (mLock) {
+            if (DEBUG_SPEW) {
+                Slog.d(TAG, "acquireWakeLockInternal: lock=" + Objects.hashCode(lock)
+                        + ", flags=0x" + Integer.toHexString(flags)
+                        + ", tag=\"" + tag + "\", ws=" + ws + ", uid=" + uid + ", pid=" + pid);
             }
-        }
-    }
 
-    void noteStopWakeLocked(WakeLock wl, WorkSource ws) {
-        if (wl.monitorType >= 0) {
-            long origId = Binder.clearCallingIdentity();
-            try {
-                if (ws != null) {
-                    mBatteryStats.noteStopWakelockFromSource(ws, wl.pid, wl.tag,
-                            wl.monitorType);
-                } else {
-                    mBatteryStats.noteStopWakelock(wl.uid, wl.pid, wl.tag, wl.monitorType);
-                }
-            } catch (RemoteException e) {
-                // Ignore
-            } finally {
-                Binder.restoreCallingIdentity(origId);
-            }
-        }
-    }
-
-    public void acquireWakeLockLocked(int flags, IBinder lock, int uid, int pid, String tag,
-            WorkSource ws) {
-        if (DEBUG) {
-            Slog.d(TAG, "acquireWakeLock flags=0x" + Integer.toHexString(flags) + " tag=" + tag);
-        }
-
-        if (ws != null && ws.size() == 0) {
-            ws = null;
-        }
-
-        int index = mLocks.getIndex(lock);
-        WakeLock wl;
-        boolean newlock;
-        boolean diffsource;
-        WorkSource oldsource;
-        if (index < 0) {
-            wl = new WakeLock(flags, lock, tag, uid, pid);
-            switch (wl.flags & LOCK_MASK)
-            {
-                case PowerManager.FULL_WAKE_LOCK:
-                    if (mUseSoftwareAutoBrightness) {
-                        wl.minState = SCREEN_BRIGHT;
-                    } else {
-                        wl.minState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
-                    }
-                    break;
-                case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
-                    wl.minState = SCREEN_BRIGHT;
-                    break;
-                case PowerManager.SCREEN_DIM_WAKE_LOCK:
-                    wl.minState = SCREEN_DIM;
-                    break;
-                case PowerManager.PARTIAL_WAKE_LOCK:
-                case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
-                    break;
-                default:
-                    // just log and bail.  we're in the server, so don't
-                    // throw an exception.
-                    Slog.e(TAG, "bad wakelock type for lock '" + tag + "' "
-                            + " flags=" + flags);
-                    return;
-            }
-            mLocks.addLock(wl);
-            if (ws != null) {
-                wl.ws = new WorkSource(ws);
-            }
-            newlock = true;
-            diffsource = false;
-            oldsource = null;
-        } else {
-            wl = mLocks.get(index);
-            newlock = false;
-            oldsource = wl.ws;
-            if (oldsource != null) {
-                if (ws == null) {
-                    wl.ws = null;
-                    diffsource = true;
-                } else {
-                    diffsource = oldsource.diff(ws);
-                }
-            } else if (ws != null) {
-                diffsource = true;
-            } else {
-                diffsource = false;
-            }
-            if (diffsource) {
-                wl.ws = new WorkSource(ws);
-            }
-        }
-        if (isScreenLock(flags)) {
-            // if this causes a wakeup, we reactivate all of the locks and
-            // set it to whatever they want.  otherwise, we modulate that
-            // by the current state so we never turn it more on than
-            // it already is.
-            if ((flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
-                mProximityWakeLockCount++;
-                if (mProximityWakeLockCount == 1) {
-                    enableProximityLockLocked();
+            WakeLock wakeLock;
+            int index = findWakeLockIndexLocked(lock);
+            if (index >= 0) {
+                wakeLock = mWakeLocks.get(index);
+                if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) {
+                    // Update existing wake lock.  This shouldn't happen but is harmless.
+                    notifyWakeLockReleasedLocked(wakeLock);
+                    wakeLock.updateProperties(flags, tag, ws, uid, pid);
+                    notifyWakeLockAcquiredLocked(wakeLock);
                 }
             } else {
-                if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
-                    int oldWakeLockState = mWakeLockState;
-                    mWakeLockState = mLocks.reactivateScreenLocksLocked();
-
-                    // Disable proximity sensor if if user presses power key while we are in the
-                    // "waiting for proximity sensor to go negative" state.
-                    if ((mWakeLockState & SCREEN_ON_BIT) != 0
-                            && mProximitySensorActive && mProximityWakeLockCount == 0) {
-                        mProximitySensorActive = false;
-                    }
-
-                    if (DEBUG) {
-                        Slog.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState)
-                                + " mWakeLockState=0x"
-                                + Integer.toHexString(mWakeLockState)
-                                + " previous wakeLockState=0x"
-                                + Integer.toHexString(oldWakeLockState));
-                    }
-                } else {
-                    if (DEBUG) {
-                        Slog.d(TAG, "here mUserState=0x" + Integer.toHexString(mUserState)
-                                + " mLocks.gatherState()=0x"
-                                + Integer.toHexString(mLocks.gatherState())
-                                + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState));
-                    }
-                    mWakeLockState = (mUserState | mWakeLockState) & mLocks.gatherState();
+                wakeLock = new WakeLock(lock, flags, tag, ws, uid, pid);
+                try {
+                    lock.linkToDeath(wakeLock, 0);
+                } catch (RemoteException ex) {
+                    throw new IllegalArgumentException("Wake lock is already dead.");
                 }
-                setPowerState(mWakeLockState | mUserState);
+                notifyWakeLockAcquiredLocked(wakeLock);
+                mWakeLocks.add(wakeLock);
             }
-        }
-        else if ((flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) {
-            if (newlock) {
-                mPartialCount++;
-                if (mPartialCount == 1) {
-                    if (LOG_PARTIAL_WL) {
-                        EventLog.writeEvent(EventLogTags.POWER_PARTIAL_WAKE_STATE, 1, tag);
-                    }
-                }
-            }
-            nativeAcquireWakeLock(PARTIAL_WAKE_LOCK_ID, PARTIAL_NAME);
-        }
 
-        if (diffsource) {
-            // If the lock sources have changed, need to first release the
-            // old ones.
-            noteStopWakeLocked(wl, oldsource);
-        }
-        if (newlock || diffsource) {
-            noteStartWakeLocked(wl, ws);
+            applyWakeLockFlagsOnAcquireLocked(wakeLock);
+            mDirty |= DIRTY_WAKE_LOCKS;
+            updatePowerStateLocked();
         }
     }
 
-    public void updateWakeLockWorkSource(IBinder lock, WorkSource ws) {
-        int uid = Binder.getCallingUid();
-        int pid = Binder.getCallingPid();
-        if (ws != null && ws.size() == 0) {
-            ws = null;
-        }
-        if (ws != null) {
-            enforceWakeSourcePermission(uid, pid);
-        }
-        synchronized (mLocks) {
-            int index = mLocks.getIndex(lock);
-            if (index < 0) {
-                throw new IllegalArgumentException("Wake lock not active");
-            }
-            WakeLock wl = mLocks.get(index);
-            WorkSource oldsource = wl.ws;
-            wl.ws = ws != null ? new WorkSource(ws) : null;
-            noteStopWakeLocked(wl, oldsource);
-            noteStartWakeLocked(wl, ws);
+    private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock) {
+        if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
+            wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
         }
     }
 
+    @Override // Binder call
     public void releaseWakeLock(IBinder lock, int flags) {
-        int uid = Binder.getCallingUid();
-        if (uid != Process.myUid()) {
-            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
+        if (lock == null) {
+            throw new IllegalArgumentException("lock must not be null");
         }
 
-        synchronized (mLocks) {
-            releaseWakeLockLocked(lock, flags, false);
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            releaseWakeLockInternal(lock, flags);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
-    private void releaseWakeLockLocked(IBinder lock, int flags, boolean death) {
-        WakeLock wl = mLocks.removeLock(lock);
-        if (wl == null) {
-            return;
-        }
-
-        if (DEBUG) {
-            Slog.d(TAG, "releaseWakeLock flags=0x"
-                    + Integer.toHexString(wl.flags) + " tag=" + wl.tag);
-        }
-
-        if (isScreenLock(wl.flags)) {
-            if ((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) {
-                mProximityWakeLockCount--;
-                if (mProximityWakeLockCount == 0) {
-                    if (mProximitySensorActive &&
-                            ((flags & PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE) != 0)) {
-                        // wait for proximity sensor to go negative before disabling sensor
-                        if (DEBUG_PROXIMITY_SENSOR) {
-                            Slog.d(TAG, "waiting for proximity sensor to go negative");
-                        }
-                    } else {
-                        disableProximityLockLocked();
-                    }
-                }
-            } else {
-                mWakeLockState = mLocks.gatherState();
-                // goes in the middle to reduce flicker
-                if ((wl.flags & PowerManager.ON_AFTER_RELEASE) != 0) {
-                    userActivity(SystemClock.uptimeMillis(), -1, false, PowerManager.USER_ACTIVITY_EVENT_OTHER, false, true);
-                }
-                setPowerState(mWakeLockState | mUserState);
-            }
-        }
-        else if ((wl.flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) {
-            mPartialCount--;
-            if (mPartialCount == 0) {
-                if (LOG_PARTIAL_WL) {
-                    EventLog.writeEvent(EventLogTags.POWER_PARTIAL_WAKE_STATE, 0, wl.tag);
-                }
-                nativeReleaseWakeLock(PARTIAL_NAME);
-            }
-        }
-        // Unlink the lock from the binder.
-        wl.binder.unlinkToDeath(wl, 0);
-
-        noteStopWakeLocked(wl, wl.ws);
-    }
-
-    private class PokeLock implements IBinder.DeathRecipient
-    {
-        PokeLock(int p, IBinder b, String t) {
-            super();
-            this.pokey = p;
-            this.binder = b;
-            this.tag = t;
-            try {
-                b.linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                binderDied();
-            }
-        }
-        public void binderDied() {
-            setPokeLock(0, this.binder, this.tag);
-        }
-        int pokey;
-        IBinder binder;
-        String tag;
-        boolean awakeOnSet;
-    }
-
-    public void setPokeLock(int pokey, IBinder token, String tag) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-        if (token == null) {
-            Slog.e(TAG, "setPokeLock got null token for tag='" + tag + "'");
-            return;
-        }
-
-        if ((pokey & POKE_LOCK_TIMEOUT_MASK) == POKE_LOCK_TIMEOUT_MASK) {
-            throw new IllegalArgumentException("setPokeLock can't have both POKE_LOCK_SHORT_TIMEOUT"
-                    + " and POKE_LOCK_MEDIUM_TIMEOUT");
-        }
-
-        synchronized (mLocks) {
-            if (pokey != 0) {
-                PokeLock p = mPokeLocks.get(token);
-                int oldPokey = 0;
-                if (p != null) {
-                    oldPokey = p.pokey;
-                    p.pokey = pokey;
-                } else {
-                    p = new PokeLock(pokey, token, tag);
-                    mPokeLocks.put(token, p);
-                }
-                int oldTimeout = oldPokey & POKE_LOCK_TIMEOUT_MASK;
-                int newTimeout = pokey & POKE_LOCK_TIMEOUT_MASK;
-                if (((mPowerState & SCREEN_ON_BIT) == 0) && (oldTimeout != newTimeout)) {
-                    p.awakeOnSet = true;
-                }
-            } else {
-                PokeLock rLock = mPokeLocks.remove(token);
-                if (rLock != null) {
-                    token.unlinkToDeath(rLock, 0);
-                }
+    private void releaseWakeLockInternal(IBinder lock, int flags) {
+        synchronized (mLock) {
+            if (DEBUG_SPEW) {
+                Slog.d(TAG, "releaseWakeLockInternal: lock=" + Objects.hashCode(lock)
+                        + ", flags=0x" + Integer.toHexString(flags));
             }
 
-            int oldPokey = mPokey;
-            int cumulative = 0;
-            boolean awakeOnSet = false;
-            for (PokeLock p: mPokeLocks.values()) {
-                cumulative |= p.pokey;
-                if (p.awakeOnSet) {
-                    awakeOnSet = true;
-                }
-            }
-            mPokey = cumulative;
-            mPokeAwakeOnSet = awakeOnSet;
-
-            int oldCumulativeTimeout = oldPokey & POKE_LOCK_TIMEOUT_MASK;
-            int newCumulativeTimeout = pokey & POKE_LOCK_TIMEOUT_MASK;
-
-            if (oldCumulativeTimeout != newCumulativeTimeout) {
-                setScreenOffTimeoutsLocked();
-                // reset the countdown timer, but use the existing nextState so it doesn't
-                // change anything
-                setTimeoutLocked(SystemClock.uptimeMillis(), mTimeoutTask.nextState);
-            }
-        }
-    }
-
-    private static String lockType(int type)
-    {
-        switch (type)
-        {
-            case PowerManager.FULL_WAKE_LOCK:
-                return "FULL_WAKE_LOCK                ";
-            case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
-                return "SCREEN_BRIGHT_WAKE_LOCK       ";
-            case PowerManager.SCREEN_DIM_WAKE_LOCK:
-                return "SCREEN_DIM_WAKE_LOCK          ";
-            case PowerManager.PARTIAL_WAKE_LOCK:
-                return "PARTIAL_WAKE_LOCK             ";
-            case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
-                return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
-            default:
-                return "???                           ";
-        }
-    }
-
-    private static String dumpPowerState(int state) {
-        return (((state & KEYBOARD_BRIGHT_BIT) != 0)
-                        ? "KEYBOARD_BRIGHT_BIT " : "")
-                + (((state & SCREEN_BRIGHT_BIT) != 0)
-                        ? "SCREEN_BRIGHT_BIT " : "")
-                + (((state & SCREEN_ON_BIT) != 0)
-                        ? "SCREEN_ON_BIT " : "")
-                + (((state & BUTTON_BRIGHT_BIT) != 0)
-                        ? "BUTTON_BRIGHT_BIT " : "")
-                + (((state & BATTERY_LOW_BIT) != 0)
-                        ? "BATTERY_LOW_BIT " : "");
-    }
-
-    @Override
-    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump PowerManager from from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid());
-            return;
-        }
-
-        long now = SystemClock.uptimeMillis();
-
-        synchronized (mLocks) {
-            pw.println("Power Manager State:");
-            pw.println("  mIsPowered=" + mIsPowered
-                    + " mPowerState=" + mPowerState
-                    + " mScreenOffTime=" + (SystemClock.elapsedRealtime()-mScreenOffTime)
-                    + " ms");
-            pw.println("  mPartialCount=" + mPartialCount);
-            pw.println("  mWakeLockState=" + dumpPowerState(mWakeLockState));
-            pw.println("  mUserState=" + dumpPowerState(mUserState));
-            pw.println("  mPowerState=" + dumpPowerState(mPowerState));
-            pw.println("  mLocks.gather=" + dumpPowerState(mLocks.gatherState()));
-            pw.println("  mNextTimeout=" + mNextTimeout + " now=" + now
-                    + " " + ((mNextTimeout-now)/1000) + "s from now");
-            pw.println("  mDimScreen=" + mDimScreen
-                    + " mStayOnConditions=" + mStayOnConditions
-                    + " mPreparingForScreenOn=" + mPreparingForScreenOn
-                    + " mSkippedScreenOn=" + mSkippedScreenOn);
-            pw.println("  mScreenOffReason=" + mScreenOffReason
-                    + " mUserState=" + mUserState);
-            pw.println("  mBroadcastQueue={" + mBroadcastQueue[0] + ',' + mBroadcastQueue[1]
-                    + ',' + mBroadcastQueue[2] + "}");
-            pw.println("  mBroadcastWhy={" + mBroadcastWhy[0] + ',' + mBroadcastWhy[1]
-                    + ',' + mBroadcastWhy[2] + "}");
-            pw.println("  mPokey=" + mPokey + " mPokeAwakeonSet=" + mPokeAwakeOnSet);
-            pw.println("  mKeyboardVisible=" + mKeyboardVisible
-                    + " mUserActivityAllowed=" + mUserActivityAllowed);
-            pw.println("  mKeylightDelay=" + mKeylightDelay + " mDimDelay=" + mDimDelay
-                    + " mScreenOffDelay=" + mScreenOffDelay);
-            pw.println("  mPreventScreenOn=" + mPreventScreenOn
-                    + "  mScreenBrightnessOverride=" + mScreenBrightnessOverride
-                    + "  mButtonBrightnessOverride=" + mButtonBrightnessOverride);
-            pw.println("  mScreenOffTimeoutSetting=" + mScreenOffTimeoutSetting
-                    + " mMaximumScreenOffTimeout=" + mMaximumScreenOffTimeout);
-            pw.println("  mLastScreenOnTime=" + mLastScreenOnTime);
-            pw.println("  mBroadcastWakeLock=" + mBroadcastWakeLock);
-            pw.println("  mStayOnWhilePluggedInScreenDimLock=" + mStayOnWhilePluggedInScreenDimLock);
-            pw.println("  mStayOnWhilePluggedInPartialLock=" + mStayOnWhilePluggedInPartialLock);
-            pw.println("  mPreventScreenOnPartialLock=" + mPreventScreenOnPartialLock);
-            pw.println("  mProximityPartialLock=" + mProximityPartialLock);
-            pw.println("  mProximityWakeLockCount=" + mProximityWakeLockCount);
-            pw.println("  mProximitySensorEnabled=" + mProximitySensorEnabled);
-            pw.println("  mProximitySensorActive=" + mProximitySensorActive);
-            pw.println("  mProximityPendingValue=" + mProximityPendingValue);
-            pw.println("  mLastProximityEventTime=" + mLastProximityEventTime);
-            pw.println("  mLightSensorEnabled=" + mLightSensorEnabled
-                    + " mLightSensorAdjustSetting=" + mLightSensorAdjustSetting);
-            pw.println("  mLightSensorValue=" + mLightSensorValue
-                    + " mLightSensorPendingValue=" + mLightSensorPendingValue);
-            pw.println("  mHighestLightSensorValue=" + mHighestLightSensorValue
-                    + " mWaitingForFirstLightSensor=" + mWaitingForFirstLightSensor);
-            pw.println("  mLightSensorPendingDecrease=" + mLightSensorPendingDecrease
-                    + " mLightSensorPendingIncrease=" + mLightSensorPendingIncrease);
-            pw.println("  mLightSensorScreenBrightness=" + mLightSensorScreenBrightness
-                    + " mLightSensorButtonBrightness=" + mLightSensorButtonBrightness
-                    + " mLightSensorKeyboardBrightness=" + mLightSensorKeyboardBrightness);
-            pw.println("  mUseSoftwareAutoBrightness=" + mUseSoftwareAutoBrightness);
-            pw.println("  mAutoBrightessEnabled=" + mAutoBrightessEnabled);
-            mScreenBrightnessAnimator.dump(pw, "mScreenBrightnessAnimator: ");
-
-            int N = mLocks.size();
-            pw.println();
-            pw.println("mLocks.size=" + N + ":");
-            for (int i=0; i<N; i++) {
-                WakeLock wl = mLocks.get(i);
-                String type = lockType(wl.flags & LOCK_MASK);
-                String acquireCausesWakeup = "";
-                if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
-                    acquireCausesWakeup = "ACQUIRE_CAUSES_WAKEUP ";
-                }
-                String activated = "";
-                if (wl.activated) {
-                   activated = " activated";
-                }
-                pw.println("  " + type + " '" + wl.tag + "'" + acquireCausesWakeup
-                        + activated + " (minState=" + wl.minState + ", uid=" + wl.uid
-                        + ", pid=" + wl.pid + ")");
-            }
-
-            pw.println();
-            pw.println("mPokeLocks.size=" + mPokeLocks.size() + ":");
-            for (PokeLock p: mPokeLocks.values()) {
-                pw.println("    poke lock '" + p.tag + "':"
-                        + ((p.pokey & POKE_LOCK_IGNORE_TOUCH_EVENTS) != 0
-                                ? " POKE_LOCK_IGNORE_TOUCH_EVENTS" : "")
-                        + ((p.pokey & POKE_LOCK_SHORT_TIMEOUT) != 0
-                                ? " POKE_LOCK_SHORT_TIMEOUT" : "")
-                        + ((p.pokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0
-                                ? " POKE_LOCK_MEDIUM_TIMEOUT" : ""));
-            }
-
-            pw.println();
-        }
-    }
-
-    private void setTimeoutLocked(long now, int nextState) {
-        setTimeoutLocked(now, -1, nextState);
-    }
-
-    // If they gave a timeoutOverride it is the number of seconds
-    // to screen-off.  Figure out where in the countdown cycle we
-    // should jump to.
-    private void setTimeoutLocked(long now, final long originalTimeoutOverride, int nextState) {
-        long timeoutOverride = originalTimeoutOverride;
-        if (mBootCompleted) {
-            synchronized (mLocks) {
-                long when = 0;
-                if (timeoutOverride <= 0) {
-                    switch (nextState)
-                    {
-                        case SCREEN_BRIGHT:
-                            when = now + mKeylightDelay;
-                            break;
-                        case SCREEN_DIM:
-                            if (mDimDelay >= 0) {
-                                when = now + mDimDelay;
-                                break;
-                            } else {
-                                Slog.w(TAG, "mDimDelay=" + mDimDelay + " while trying to dim");
-                            }
-                       case SCREEN_OFF:
-                            synchronized (mLocks) {
-                                when = now + mScreenOffDelay;
-                            }
-                            break;
-                        default:
-                            when = now;
-                            break;
-                    }
-                } else {
-                    override: {
-                        if (timeoutOverride <= mScreenOffDelay) {
-                            when = now + timeoutOverride;
-                            nextState = SCREEN_OFF;
-                            break override;
-                        }
-                        timeoutOverride -= mScreenOffDelay;
-
-                        if (mDimDelay >= 0) {
-                             if (timeoutOverride <= mDimDelay) {
-                                when = now + timeoutOverride;
-                                nextState = SCREEN_DIM;
-                                break override;
-                            }
-                            timeoutOverride -= mDimDelay;
-                        }
-
-                        when = now + timeoutOverride;
-                        nextState = SCREEN_BRIGHT;
-                    }
-                }
-                if (DEBUG) {
-                    Slog.d(TAG, "setTimeoutLocked now=" + now
-                            + " timeoutOverride=" + timeoutOverride
-                            + " nextState=" + nextState + " when=" + when);
-                }
-
-                mHandler.removeCallbacks(mTimeoutTask);
-                mTimeoutTask.nextState = nextState;
-                mTimeoutTask.remainingTimeoutOverride = timeoutOverride > 0
-                        ? (originalTimeoutOverride - timeoutOverride)
-                        : -1;
-                mHandler.postAtTime(mTimeoutTask, when);
-                mNextTimeout = when; // for debugging
-            }
-        }
-    }
-
-    private void cancelTimerLocked()
-    {
-        mHandler.removeCallbacks(mTimeoutTask);
-        mTimeoutTask.nextState = -1;
-    }
-
-    private class TimeoutTask implements Runnable
-    {
-        int nextState; // access should be synchronized on mLocks
-        long remainingTimeoutOverride;
-        public void run()
-        {
-            synchronized (mLocks) {
-                if (DEBUG) {
-                    Slog.d(TAG, "user activity timeout timed out nextState=" + this.nextState);
-                }
-
-                if (nextState == -1) {
-                    return;
-                }
-
-                mUserState = this.nextState;
-                setPowerState(this.nextState | mWakeLockState);
-
-                long now = SystemClock.uptimeMillis();
-
-                switch (this.nextState)
-                {
-                    case SCREEN_BRIGHT:
-                        if (mDimDelay >= 0) {
-                            setTimeoutLocked(now, remainingTimeoutOverride, SCREEN_DIM);
-                            break;
-                        }
-                    case SCREEN_DIM:
-                        setTimeoutLocked(now, remainingTimeoutOverride, SCREEN_OFF);
-                        break;
-                }
-            }
-        }
-    }
-
-    private void sendNotificationLocked(boolean on, int why) {
-        if (!mInitialized) {
-            // No notifications sent until first initialization is done.
-            // This is so that when we are moving from our initial state
-            // which looks like the screen was off to it being on, we do not
-            // go through the process of waiting for the higher-level user
-            // space to be ready before turning up the display brightness.
-            // (And also do not send needless broadcasts about the screen.)
-            return;
-        }
-
-        if (DEBUG_SCREEN_ON) {
-            RuntimeException here = new RuntimeException("here");
-            here.fillInStackTrace();
-            Slog.i(TAG, "sendNotificationLocked: " + on, here);
-        }
-
-        if (!on) {
-            mStillNeedSleepNotification = false;
-        }
-
-        // Add to the queue.
-        int index = 0;
-        while (mBroadcastQueue[index] != -1) {
-            index++;
-        }
-        mBroadcastQueue[index] = on ? 1 : 0;
-        mBroadcastWhy[index] = why;
-
-        // If we added it position 2, then there is a pair that can be stripped.
-        // If we added it position 1 and we're turning the screen off, we can strip
-        // the pair and do nothing, because the screen is already off, and therefore
-        // keyguard has already been enabled.
-        // However, if we added it at position 1 and we're turning it on, then position
-        // 0 was to turn it off, and we can't strip that, because keyguard needs to come
-        // on, so have to run the queue then.
-        if (index == 2) {
-            // While we're collapsing them, if it's going off, and the new reason
-            // is more significant than the first, then use the new one.
-            if (!on && mBroadcastWhy[0] > why) {
-                mBroadcastWhy[0] = why;
-            }
-            mBroadcastQueue[0] = on ? 1 : 0;
-            mBroadcastQueue[1] = -1;
-            mBroadcastQueue[2] = -1;
-            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount);
-            mBroadcastWakeLock.release();
-            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount);
-            mBroadcastWakeLock.release();
-            index = 0;
-        }
-        if (index == 1 && !on) {
-            mBroadcastQueue[0] = -1;
-            mBroadcastQueue[1] = -1;
-            index = -1;
-            // The wake lock was being held, but we're not actually going to do any
-            // broadcasts, so release the wake lock.
-            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount);
-            mBroadcastWakeLock.release();
-        }
-
-        // The broadcast queue has changed; make sure the screen is on if it
-        // is now possible for it to be.
-        if (mSkippedScreenOn) {
-            updateLightsLocked(mPowerState, SCREEN_ON_BIT);
-        }
-
-        // Now send the message.
-        if (index >= 0) {
-            // Acquire the broadcast wake lock before changing the power
-            // state. It will be release after the broadcast is sent.
-            // We always increment the ref count for each notification in the queue
-            // and always decrement when that notification is handled.
-            mBroadcastWakeLock.acquire();
-            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND, mBroadcastWakeLock.mCount);
-            mHandler.post(mNotificationTask);
-        }
-    }
-
-    private WindowManagerPolicy.ScreenOnListener mScreenOnListener =
-            new WindowManagerPolicy.ScreenOnListener() {
-                public void onScreenOn() {
-                    synchronized (mLocks) {
-                        if (mPreparingForScreenOn) {
-                            mPreparingForScreenOn = false;
-                            updateLightsLocked(mPowerState, SCREEN_ON_BIT);
-                            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP,
-                                    4, mBroadcastWakeLock.mCount);
-                            mBroadcastWakeLock.release();
-                        }
-                    }
-                }
-    };
-
-    private Runnable mNotificationTask = new Runnable()
-    {
-        public void run()
-        {
-            while (true) {
-                int value;
-                int why;
-                WindowManagerPolicy policy;
-                synchronized (mLocks) {
-                    value = mBroadcastQueue[0];
-                    why = mBroadcastWhy[0];
-                    for (int i=0; i<2; i++) {
-                        mBroadcastQueue[i] = mBroadcastQueue[i+1];
-                        mBroadcastWhy[i] = mBroadcastWhy[i+1];
-                    }
-                    policy = getPolicyLocked();
-                    if (value == 1 && !mPreparingForScreenOn) {
-                        mPreparingForScreenOn = true;
-                        mBroadcastWakeLock.acquire();
-                        EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_SEND,
-                                mBroadcastWakeLock.mCount);
-                    }
-                }
-                if (value == 1) {
-                    mScreenOnStart = SystemClock.uptimeMillis();
-
-                    policy.screenTurningOn(mScreenOnListener);
-                    try {
-                        ActivityManagerNative.getDefault().wakingUp();
-                    } catch (RemoteException e) {
-                        // ignore it
-                    }
-
-                    if (DEBUG) {
-                        Slog.d(TAG, "mBroadcastWakeLock=" + mBroadcastWakeLock);
-                    }
-                    if (mContext != null && ActivityManagerNative.isSystemReady()) {
-                        mContext.sendOrderedBroadcast(mScreenOnIntent, null,
-                                mScreenOnBroadcastDone, mHandler, 0, null, null);
-                    } else {
-                        synchronized (mLocks) {
-                            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2,
-                                    mBroadcastWakeLock.mCount);
-                            mBroadcastWakeLock.release();
-                        }
-                    }
-                }
-                else if (value == 0) {
-                    mScreenOffStart = SystemClock.uptimeMillis();
-
-                    policy.screenTurnedOff(why);
-                    try {
-                        ActivityManagerNative.getDefault().goingToSleep();
-                    } catch (RemoteException e) {
-                        // ignore it.
-                    }
-
-                    if (mContext != null && ActivityManagerNative.isSystemReady()) {
-                        mContext.sendOrderedBroadcast(mScreenOffIntent, null,
-                                mScreenOffBroadcastDone, mHandler, 0, null, null);
-                    } else {
-                        synchronized (mLocks) {
-                            EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3,
-                                    mBroadcastWakeLock.mCount);
-                            updateLightsLocked(mPowerState, SCREEN_ON_BIT);
-                            mBroadcastWakeLock.release();
-                        }
-                    }
-                }
-                else {
-                    // If we're in this case, then this handler is running for a previous
-                    // paired transaction.  mBroadcastWakeLock will already have been released.
-                    break;
-                }
-            }
-        }
-    };
-
-    long mScreenOnStart;
-    private BroadcastReceiver mScreenOnBroadcastDone = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            synchronized (mLocks) {
-                EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
-                        SystemClock.uptimeMillis() - mScreenOnStart, mBroadcastWakeLock.mCount);
-                mBroadcastWakeLock.release();
-            }
-        }
-    };
-
-    long mScreenOffStart;
-    private BroadcastReceiver mScreenOffBroadcastDone = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            synchronized (mLocks) {
-                EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0,
-                        SystemClock.uptimeMillis() - mScreenOffStart, mBroadcastWakeLock.mCount);
-                mBroadcastWakeLock.release();
-            }
-        }
-    };
-
-    /**
-     * Prevents the screen from turning on even if it *should* turn on due
-     * to a subsequent full wake lock being acquired.
-     * <p>
-     * This is a temporary hack that allows an activity to "cover up" any
-     * display glitches that happen during the activity's startup
-     * sequence.  (Specifically, this API was added to work around a
-     * cosmetic bug in the "incoming call" sequence, where the lock screen
-     * would flicker briefly before the incoming call UI became visible.)
-     * TODO: There ought to be a more elegant way of doing this,
-     * probably by having the PowerManager and ActivityManager
-     * work together to let apps specify that the screen on/off
-     * state should be synchronized with the Activity lifecycle.
-     * <p>
-     * Note that calling preventScreenOn(true) will NOT turn the screen
-     * off if it's currently on.  (This API only affects *future*
-     * acquisitions of full wake locks.)
-     * But calling preventScreenOn(false) WILL turn the screen on if
-     * it's currently off because of a prior preventScreenOn(true) call.
-     * <p>
-     * Any call to preventScreenOn(true) MUST be followed promptly by a call
-     * to preventScreenOn(false).  In fact, if the preventScreenOn(false)
-     * call doesn't occur within 5 seconds, we'll turn the screen back on
-     * ourselves (and log a warning about it); this prevents a buggy app
-     * from disabling the screen forever.)
-     * <p>
-     * TODO: this feature should really be controlled by a new type of poke
-     * lock (rather than an IPowerManager call).
-     */
-    public void preventScreenOn(boolean prevent) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-
-        synchronized (mLocks) {
-            if (prevent) {
-                // First of all, grab a partial wake lock to
-                // make sure the CPU stays on during the entire
-                // preventScreenOn(true) -> preventScreenOn(false) sequence.
-                mPreventScreenOnPartialLock.acquire();
-
-                // Post a forceReenableScreen() call (for 5 seconds in the
-                // future) to make sure the matching preventScreenOn(false) call
-                // has happened by then.
-                mHandler.removeCallbacks(mForceReenableScreenTask);
-                mHandler.postDelayed(mForceReenableScreenTask, 5000);
-
-                // Finally, set the flag that prevents the screen from turning on.
-                // (Below, in setPowerState(), we'll check mPreventScreenOn and
-                // we *won't* call setScreenStateLocked(true) if it's set.)
-                mPreventScreenOn = true;
-            } else {
-                // (Re)enable the screen.
-                mPreventScreenOn = false;
-
-                // We're "undoing" a the prior preventScreenOn(true) call, so we
-                // no longer need the 5-second safeguard.
-                mHandler.removeCallbacks(mForceReenableScreenTask);
-
-                // Forcibly turn on the screen if it's supposed to be on.  (This
-                // handles the case where the screen is currently off because of
-                // a prior preventScreenOn(true) call.)
-                if (!mProximitySensorActive && (mPowerState & SCREEN_ON_BIT) != 0) {
-                    if (DEBUG) {
-                        Slog.d(TAG,
-                              "preventScreenOn: turning on after a prior preventScreenOn(true)!");
-                    }
-                    int err = setScreenStateLocked(true);
-                    if (err != 0) {
-                        Slog.w(TAG, "preventScreenOn: error from setScreenStateLocked(): " + err);
-                    }
-                }
-
-                // Release the partial wake lock that we held during the
-                // preventScreenOn(true) -> preventScreenOn(false) sequence.
-                mPreventScreenOnPartialLock.release();
-            }
-        }
-    }
-
-    public void setScreenBrightnessOverride(int brightness) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-
-        if (DEBUG) Slog.d(TAG, "setScreenBrightnessOverride " + brightness);
-        synchronized (mLocks) {
-            if (mScreenBrightnessOverride != brightness) {
-                mScreenBrightnessOverride = brightness;
-                if (isScreenOn()) {
-                    updateLightsLocked(mPowerState, SCREEN_ON_BIT);
-                }
-            }
-        }
-    }
-
-    public void setButtonBrightnessOverride(int brightness) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-
-        if (DEBUG) Slog.d(TAG, "setButtonBrightnessOverride " + brightness);
-         synchronized (mLocks) {
-           if (mButtonBrightnessOverride != brightness) {
-                mButtonBrightnessOverride = brightness;
-                if (isScreenOn()) {
-                    updateLightsLocked(mPowerState, BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT);
-                }
-            }
-        }
-    }
-
-    /**
-     * Sanity-check that gets called 5 seconds after any call to
-     * preventScreenOn(true).  This ensures that the original call
-     * is followed promptly by a call to preventScreenOn(false).
-     */
-    private void forceReenableScreen() {
-        // We shouldn't get here at all if mPreventScreenOn is false, since
-        // we should have already removed any existing
-        // mForceReenableScreenTask messages...
-        if (!mPreventScreenOn) {
-            Slog.w(TAG, "forceReenableScreen: mPreventScreenOn is false, nothing to do");
-            return;
-        }
-
-        // Uh oh.  It's been 5 seconds since a call to
-        // preventScreenOn(true) and we haven't re-enabled the screen yet.
-        // This means the app that called preventScreenOn(true) is either
-        // slow (i.e. it took more than 5 seconds to call preventScreenOn(false)),
-        // or buggy (i.e. it forgot to call preventScreenOn(false), or
-        // crashed before doing so.)
-
-        // Log a warning, and forcibly turn the screen back on.
-        Slog.w(TAG, "App called preventScreenOn(true) but didn't promptly reenable the screen! "
-              + "Forcing the screen back on...");
-        preventScreenOn(false);
-    }
-
-    private Runnable mForceReenableScreenTask = new Runnable() {
-            public void run() {
-                forceReenableScreen();
-            }
-        };
-
-    private int setScreenStateLocked(boolean on) {
-        if (DEBUG_SCREEN_ON) {
-            RuntimeException e = new RuntimeException("here");
-            e.fillInStackTrace();
-            Slog.i(TAG, "Set screen state: " + on, e);
-        }
-        if (on) {
-            if (mInitialized && ((mPowerState & SCREEN_ON_BIT) == 0 || mSkippedScreenOn)) {
-                // If we are turning the screen state on, but the screen
-                // light is currently off, then make sure that we set the
-                // light at this point to 0.  This is the case where we are
-                // turning on the screen and waiting for the UI to be drawn
-                // before showing it to the user.  We want the light off
-                // until it is ready to be shown to the user, not it using
-                // whatever the last value it had.
-                // Skip this if the screen is being turned on for the first time
-                // after boot (mInitialized is false).
-                if (DEBUG_SCREEN_ON) {
-                    Slog.i(TAG, "Forcing brightness 0: mPowerState=0x"
-                            + Integer.toHexString(mPowerState)
-                            + " mSkippedScreenOn=" + mSkippedScreenOn);
-                }
-                mScreenBrightnessAnimator.animateTo(PowerManager.BRIGHTNESS_OFF, SCREEN_BRIGHT_BIT, 0);
-            }
-        }
-        int err = nativeSetScreenState(on);
-        if (err == 0) {
-            mLastScreenOnTime = (on ? SystemClock.elapsedRealtime() : 0);
-            if (mUseSoftwareAutoBrightness) {
-                enableLightSensorLocked(on);
-                if (on) {
-                    // If AutoBrightness is enabled, set the brightness immediately after the
-                    // next sensor value is received.
-                    mWaitingForFirstLightSensor = mAutoBrightessEnabled;
-                } else {
-                    // make sure button and key backlights are off too
-                    mButtonLight.turnOff();
-                    mKeyboardLight.turnOff();
-                }
-            }
-        }
-        return err;
-    }
-
-    private void setPowerState(int state)
-    {
-        setPowerState(state, false, WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT);
-    }
-
-    private void setPowerState(int newState, boolean noChangeLights, int reason)
-    {
-        synchronized (mLocks) {
-            int err;
-
-            if (DEBUG) {
-                Slog.d(TAG, "setPowerState: mPowerState=0x" + Integer.toHexString(mPowerState)
-                        + " newState=0x" + Integer.toHexString(newState)
-                        + " noChangeLights=" + noChangeLights
-                        + " reason=" + reason);
-            }
-            
-            if (noChangeLights) {
-                newState = (newState & ~LIGHTS_MASK) | (mPowerState & LIGHTS_MASK);
-            }
-            if (mProximitySensorActive) {
-                // don't turn on the screen when the proximity sensor lock is held
-                newState = (newState & ~SCREEN_BRIGHT);
-            }
-
-            if (batteryIsLow()) {
-                newState |= BATTERY_LOW_BIT;
-            } else {
-                newState &= ~BATTERY_LOW_BIT;
-            }
-            if (newState == mPowerState && mInitialized) {
+            int index = findWakeLockIndexLocked(lock);
+            if (index < 0) {
                 return;
             }
 
-            if (!mBootCompleted && !mUseSoftwareAutoBrightness) {
-                newState |= ALL_BRIGHT;
+            WakeLock wakeLock = mWakeLocks.get(index);
+            mWakeLocks.remove(index);
+            notifyWakeLockReleasedLocked(wakeLock);
+            wakeLock.mLock.unlinkToDeath(wakeLock, 0);
+
+            if ((flags & PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE) != 0) {
+                mRequestWaitForNegativeProximity = true;
             }
 
-            boolean oldScreenOn = (mPowerState & SCREEN_ON_BIT) != 0;
-            boolean newScreenOn = (newState & SCREEN_ON_BIT) != 0;
-
-            if (DEBUG) {
-                Slog.d(TAG, "setPowerState: mPowerState=" + mPowerState
-                        + " newState=" + newState + " noChangeLights=" + noChangeLights);
-                Slog.d(TAG, "  oldKeyboardBright=" + ((mPowerState & KEYBOARD_BRIGHT_BIT) != 0)
-                         + " newKeyboardBright=" + ((newState & KEYBOARD_BRIGHT_BIT) != 0));
-                Slog.d(TAG, "  oldScreenBright=" + ((mPowerState & SCREEN_BRIGHT_BIT) != 0)
-                         + " newScreenBright=" + ((newState & SCREEN_BRIGHT_BIT) != 0));
-                Slog.d(TAG, "  oldButtonBright=" + ((mPowerState & BUTTON_BRIGHT_BIT) != 0)
-                         + " newButtonBright=" + ((newState & BUTTON_BRIGHT_BIT) != 0));
-                Slog.d(TAG, "  oldScreenOn=" + oldScreenOn
-                         + " newScreenOn=" + newScreenOn);
-                Slog.d(TAG, "  oldBatteryLow=" + ((mPowerState & BATTERY_LOW_BIT) != 0)
-                         + " newBatteryLow=" + ((newState & BATTERY_LOW_BIT) != 0));
-            }
-
-            final boolean stateChanged = mPowerState != newState;
-
-            if (stateChanged && !newScreenOn && reason == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT) {
-                if (mPolicy != null && mIsPowered && mPolicy.isScreenSaverEnabled()) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "setPowerState: running screen saver instead of turning off screen");
-                    }
-                    if (mPolicy.startScreenSaver()) {
-                        // was successful
-                        return;
-                    }
-                }
-            }
-
-
-            if (oldScreenOn != newScreenOn) {
-                if (newScreenOn) {
-                    // When the user presses the power button, we need to always send out the
-                    // notification that it's going to sleep so the keyguard goes on.  But
-                    // we can't do that until the screen fades out, so we don't show the keyguard
-                    // too early.
-                    if (mStillNeedSleepNotification) {
-                        sendNotificationLocked(false, WindowManagerPolicy.OFF_BECAUSE_OF_USER);
-                    }
-
-                    // Turn on the screen UNLESS there was a prior
-                    // preventScreenOn(true) request.  (Note that the lifetime
-                    // of a single preventScreenOn() request is limited to 5
-                    // seconds to prevent a buggy app from disabling the
-                    // screen forever; see forceReenableScreen().)
-                    boolean reallyTurnScreenOn = true;
-                    if (DEBUG) {
-                        Slog.d(TAG, "- turning screen on...  mPreventScreenOn = "
-                              + mPreventScreenOn);
-                    }
-
-                    if (mPreventScreenOn) {
-                        if (DEBUG) {
-                            Slog.d(TAG, "- PREVENTING screen from really turning on!");
-                        }
-                        reallyTurnScreenOn = false;
-                    }
-                    if (reallyTurnScreenOn) {
-                        err = setScreenStateLocked(true);
-                        long identity = Binder.clearCallingIdentity();
-                        try {
-                            mBatteryStats.noteScreenBrightness(getPreferredBrightness());
-                            mBatteryStats.noteScreenOn();
-                        } catch (RemoteException e) {
-                            Slog.w(TAG, "RemoteException calling noteScreenOn on BatteryStatsService", e);
-                        } finally {
-                            Binder.restoreCallingIdentity(identity);
-                        }
-                    } else {
-                        setScreenStateLocked(false);
-                        // But continue as if we really did turn the screen on...
-                        err = 0;
-                    }
-
-                    EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, reason, 0, 0);
-                    if (err == 0) {
-                        sendNotificationLocked(true, -1);
-                        // Update the lights *after* taking care of turning the
-                        // screen on, so we do this after our notifications are
-                        // enqueued and thus will delay turning on the screen light
-                        // until the windows are correctly displayed.
-                        if (stateChanged) {
-                            updateLightsLocked(newState, 0);
-                        }
-                        mPowerState |= SCREEN_ON_BIT;
-                    }
-
-                } else {
-                    // Update the lights *before* taking care of turning the
-                    // screen off, so we can initiate any animations that are desired.
-                    mScreenOffReason = reason;
-                    if (stateChanged) {
-                        updateLightsLocked(newState, 0);
-                    }
-
-                    // cancel light sensor task
-                    mHandler.removeCallbacks(mAutoBrightnessTask);
-                    mLightSensorPendingDecrease = false;
-                    mLightSensorPendingIncrease = false;
-                    mScreenOffTime = SystemClock.elapsedRealtime();
-                    long identity = Binder.clearCallingIdentity();
-                    try {
-                        mBatteryStats.noteScreenOff();
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "RemoteException calling noteScreenOff on BatteryStatsService", e);
-                    } finally {
-                        Binder.restoreCallingIdentity(identity);
-                    }
-                    mPowerState &= ~SCREEN_ON_BIT;
-                    if (!mScreenBrightnessAnimator.isAnimating()) {
-                        err = screenOffFinishedAnimatingLocked(reason);
-                    } else {
-                        err = 0;
-                    }
-
-                    // stop the screensaver if user turned screen off
-                    if (stateChanged && reason == WindowManagerPolicy.OFF_BECAUSE_OF_USER) {
-                        if (mPolicy != null) {
-                            mPolicy.stopScreenSaver();
-                        }
-                    }
-                }
-            } else if (stateChanged) {
-                // Screen on/off didn't change, but lights may have.
-                updateLightsLocked(newState, 0);
-            }
-
-            mPowerState = (mPowerState & ~LIGHTS_MASK) | (newState & LIGHTS_MASK);
-
-            updateNativePowerStateLocked();
+            applyWakeLockFlagsOnReleaseLocked(wakeLock);
+            mDirty |= DIRTY_WAKE_LOCKS;
+            updatePowerStateLocked();
         }
     }
 
-    private void updateNativePowerStateLocked() {
-        if (!mHeadless) {
-            nativeSetPowerState(
-                    (mPowerState & SCREEN_ON_BIT) != 0,
-                    (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT);
+    private void handleWakeLockDeath(WakeLock wakeLock) {
+        synchronized (mLock) {
+            if (DEBUG_SPEW) {
+                Slog.d(TAG, "handleWakeLockDeath: lock=" + Objects.hashCode(wakeLock.mLock));
+            }
+
+            int index = mWakeLocks.indexOf(wakeLock);
+            if (index < 0) {
+                return;
+            }
+
+            mWakeLocks.remove(index);
+            notifyWakeLockReleasedLocked(wakeLock);
+
+            applyWakeLockFlagsOnReleaseLocked(wakeLock);
+            mDirty |= DIRTY_WAKE_LOCKS;
+            updatePowerStateLocked();
         }
     }
 
-    private int screenOffFinishedAnimatingLocked(int reason) {
-        // I don't think we need to check the current state here because all of these
-        // Power.setScreenState and sendNotificationLocked can both handle being
-        // called multiple times in the same state. -joeo
-        EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, reason, 0, 0);
-        int err = setScreenStateLocked(false);
-        if (err == 0) {
-            mScreenOffReason = reason;
-            sendNotificationLocked(false, reason);
+    private void applyWakeLockFlagsOnReleaseLocked(WakeLock wakeLock) {
+        if ((wakeLock.mFlags & PowerManager.ON_AFTER_RELEASE) != 0) {
+            userActivityNoUpdateLocked(SystemClock.uptimeMillis(),
+                    PowerManager.USER_ACTIVITY_EVENT_OTHER,
+                    PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS,
+                    wakeLock.mOwnerUid);
         }
-        return err;
     }
 
-    private boolean batteryIsLow() {
-        return (!mIsPowered &&
-                mBatteryService.getBatteryLevel() <= LOW_BATTERY_THRESHOLD);
-    }
+    @Override // Binder call
+    public void updateWakeLockWorkSource(IBinder lock, WorkSource ws) {
+        if (lock == null) {
+            throw new IllegalArgumentException("lock must not be null");
+        }
 
-    private boolean shouldDeferScreenOnLocked() {
-        if (mPreparingForScreenOn) {
-            // Currently waiting for confirmation from the policy that it
-            // is okay to turn on the screen.  Don't allow the screen to go
-            // on until that is done.
-            if (DEBUG_SCREEN_ON) Slog.i(TAG,
-                    "updateLights: delaying screen on due to mPreparingForScreenOn");
-            return true;
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
+        if (ws != null && ws.size() != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.UPDATE_DEVICE_STATS, null);
         } else {
-            // If there is a screen-on command in the notification queue, we
-            // can't turn the screen on until it has been processed (and we
-            // have set mPreparingForScreenOn) or it has been dropped.
-            for (int i=0; i<mBroadcastQueue.length; i++) {
-                if (mBroadcastQueue[i] == 1) {
-                    if (DEBUG_SCREEN_ON) Slog.i(TAG,
-                            "updateLights: delaying screen on due to notification queue");
+            ws = null;
+        }
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            updateWakeLockWorkSourceInternal(lock, ws);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private void updateWakeLockWorkSourceInternal(IBinder lock, WorkSource ws) {
+        synchronized (mLock) {
+            int index = findWakeLockIndexLocked(lock);
+            if (index < 0) {
+                throw new IllegalArgumentException("Wake lock not active");
+            }
+
+            WakeLock wakeLock = mWakeLocks.get(index);
+            if (!wakeLock.hasSameWorkSource(ws)) {
+                notifyWakeLockReleasedLocked(wakeLock);
+                wakeLock.updateWorkSource(ws);
+                notifyWakeLockAcquiredLocked(wakeLock);
+            }
+        }
+    }
+
+    private int findWakeLockIndexLocked(IBinder lock) {
+        final int count = mWakeLocks.size();
+        for (int i = 0; i < count; i++) {
+            if (mWakeLocks.get(i).mLock == lock) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private void notifyWakeLockAcquiredLocked(WakeLock wakeLock) {
+        if (mSystemReady) {
+            mNotifier.onWakeLockAcquired(wakeLock.mFlags, wakeLock.mTag,
+                    wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource);
+        }
+    }
+
+    private void notifyWakeLockReleasedLocked(WakeLock wakeLock) {
+        if (mSystemReady) {
+            mNotifier.onWakeLockReleased(wakeLock.mFlags, wakeLock.mTag,
+                    wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource);
+        }
+    }
+
+    @Override // Binder call
+    public boolean isWakeLockLevelSupported(int level) {
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            return isWakeLockLevelSupportedInternal(level);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private boolean isWakeLockLevelSupportedInternal(int level) {
+        synchronized (mLock) {
+            switch (level) {
+                case PowerManager.PARTIAL_WAKE_LOCK:
+                case PowerManager.SCREEN_DIM_WAKE_LOCK:
+                case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
+                case PowerManager.FULL_WAKE_LOCK:
                     return true;
-                }
+
+                case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
+                    return mSystemReady && mDisplayPowerController.isProximitySensorAvailable();
+
+                default:
+                    return false;
+            }
+        }
+    }
+
+    @Override // Binder call
+    public void userActivity(long eventTime, int event, int flags) {
+        if (eventTime > SystemClock.uptimeMillis()) {
+            throw new IllegalArgumentException("event time must not be in the future");
+        }
+
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+        final int uid = Binder.getCallingUid();
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            userActivityInternal(eventTime, event, flags, uid);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    // Called from native code.
+    private void userActivityFromNative(long eventTime, int event, int flags) {
+        userActivityInternal(eventTime, event, flags, Process.SYSTEM_UID);
+    }
+
+    private void userActivityInternal(long eventTime, int event, int flags, int uid) {
+        synchronized (mLock) {
+            if (userActivityNoUpdateLocked(eventTime, event, flags, uid)) {
+                updatePowerStateLocked();
+            }
+        }
+    }
+
+    private boolean userActivityNoUpdateLocked(long eventTime, int event, int flags, int uid) {
+        if (DEBUG_SPEW) {
+            Slog.d(TAG, "userActivityNoUpdateLocked: eventTime=" + eventTime
+                    + ", event=" + event + ", flags=0x" + Integer.toHexString(flags)
+                    + ", uid=" + uid);
+        }
+
+        if (eventTime < mLastSleepTime || eventTime < mLastWakeTime
+                || mWakefulness == WAKEFULNESS_ASLEEP || !mBootCompleted || !mSystemReady) {
+            return false;
+        }
+
+        mNotifier.onUserActivity(event, uid);
+
+        if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
+            if (eventTime > mLastUserActivityTimeNoChangeLights
+                    && eventTime > mLastUserActivityTime) {
+                mLastUserActivityTimeNoChangeLights = eventTime;
+                mDirty |= DIRTY_USER_ACTIVITY;
+                return true;
+            }
+        } else {
+            if (eventTime > mLastUserActivityTime) {
+                mLastUserActivityTime = eventTime;
+                mDirty |= DIRTY_USER_ACTIVITY;
+                return true;
             }
         }
         return false;
     }
 
-    private void updateLightsLocked(int newState, int forceState) {
-        final int oldState = mPowerState;
+    @Override // Binder call
+    public void wakeUp(long eventTime) {
+        if (eventTime > SystemClock.uptimeMillis()) {
+            throw new IllegalArgumentException("event time must not be in the future");
+        }
 
-        // If the screen is not currently on, we will want to delay actually
-        // turning the lights on if we are still getting the UI put up.
-        if ((oldState & SCREEN_ON_BIT) == 0 || mSkippedScreenOn) {
-            // Don't turn screen on until we know we are really ready to.
-            // This is to avoid letting the screen go on before things like the
-            // lock screen have been displayed.
-            if ((mSkippedScreenOn = shouldDeferScreenOnLocked())) {
-                newState &= ~(SCREEN_ON_BIT|SCREEN_BRIGHT_BIT);
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            wakeUpInternal(eventTime);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    // Called from native code.
+    private void wakeUpFromNative(long eventTime) {
+        wakeUpInternal(eventTime);
+    }
+
+    private void wakeUpInternal(long eventTime) {
+        synchronized (mLock) {
+            if (wakeUpNoUpdateLocked(eventTime)) {
+                updatePowerStateLocked();
             }
         }
+    }
 
-        if ((newState & SCREEN_ON_BIT) != 0) {
-            // Only turn on the buttons or keyboard if the screen is also on.
-            // We should never see the buttons on but not the screen.
-            newState = applyButtonState(newState);
-            newState = applyKeyboardState(newState);
+    private boolean wakeUpNoUpdateLocked(long eventTime) {
+        if (DEBUG_SPEW) {
+            Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime);
         }
-        final int realDifference = (newState ^ oldState);
-        final int difference = realDifference | forceState;
-        if (difference == 0) {
+
+        if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
+                || !mBootCompleted || !mSystemReady) {
+            return false;
+        }
+
+        switch (mWakefulness) {
+            case WAKEFULNESS_ASLEEP:
+                Slog.i(TAG, "Waking up from sleep...");
+                mNotifier.onWakeUpStarted();
+                mSendWakeUpFinishedNotificationWhenReady = true;
+                mSendGoToSleepFinishedNotificationWhenReady = false;
+                break;
+            case WAKEFULNESS_DREAMING:
+                Slog.i(TAG, "Waking up from dream...");
+                break;
+            case WAKEFULNESS_NAPPING:
+                Slog.i(TAG, "Waking up from nap...");
+                break;
+        }
+
+        mLastWakeTime = eventTime;
+        mWakefulness = WAKEFULNESS_AWAKE;
+        mDirty |= DIRTY_WAKEFULNESS;
+
+        userActivityNoUpdateLocked(
+                eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
+        return true;
+    }
+
+    @Override // Binder call
+    public void goToSleep(long eventTime, int reason) {
+        if (eventTime > SystemClock.uptimeMillis()) {
+            throw new IllegalArgumentException("event time must not be in the future");
+        }
+
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            goToSleepInternal(eventTime, reason);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    // Called from native code.
+    private void goToSleepFromNative(long eventTime, int reason) {
+        goToSleepInternal(eventTime, reason);
+    }
+
+    private void goToSleepInternal(long eventTime, int reason) {
+        synchronized (mLock) {
+            if (goToSleepNoUpdateLocked(eventTime, reason)) {
+                updatePowerStateLocked();
+            }
+        }
+    }
+
+    private boolean goToSleepNoUpdateLocked(long eventTime, int reason) {
+        if (DEBUG_SPEW) {
+            Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime + ", reason=" + reason);
+        }
+
+        if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
+                || !mBootCompleted || !mSystemReady) {
+            return false;
+        }
+
+        switch (reason) {
+            case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
+                Slog.i(TAG, "Going to sleep due to device administration policy...");
+                break;
+            case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
+                Slog.i(TAG, "Going to sleep due to screen timeout...");
+                break;
+            default:
+                Slog.i(TAG, "Going to sleep by user request...");
+                reason = PowerManager.GO_TO_SLEEP_REASON_USER;
+                break;
+        }
+
+        mLastSleepTime = eventTime;
+        mDirty |= DIRTY_WAKEFULNESS;
+        mWakefulness = WAKEFULNESS_ASLEEP;
+        mNotifier.onGoToSleepStarted(reason);
+        mSendGoToSleepFinishedNotificationWhenReady = true;
+        mSendWakeUpFinishedNotificationWhenReady = false;
+
+        // Report the number of wake locks that will be cleared by going to sleep.
+        int numWakeLocksCleared = 0;
+        final int numWakeLocks = mWakeLocks.size();
+        for (int i = 0; i < numWakeLocks; i++) {
+            final WakeLock wakeLock = mWakeLocks.get(i);
+            switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
+                case PowerManager.FULL_WAKE_LOCK:
+                case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
+                case PowerManager.SCREEN_DIM_WAKE_LOCK:
+                    numWakeLocksCleared += 1;
+                    break;
+            }
+        }
+        EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numWakeLocksCleared);
+        return true;
+    }
+
+    /**
+     * Updates the global power state based on dirty bits recorded in mDirty.
+     *
+     * This is the main function that performs power state transitions.
+     * We centralize them here so that we can recompute the power state completely
+     * each time something important changes, and ensure that we do it the same
+     * way each time.  The point is to gather all of the transition logic here.
+     */
+    private void updatePowerStateLocked() {
+        if (!mSystemReady || mDirty == 0) {
             return;
         }
 
-        int offMask = 0;
-        int dimMask = 0;
-        int onMask = 0;
+        // Phase 0: Basic state updates.
+        updateIsPoweredLocked(mDirty);
+        updateStayOnLocked(mDirty);
 
-        int preferredBrightness = getPreferredBrightness();
+        // Phase 1: Update wakefulness.
+        // Loop because the wake lock and user activity computations are influenced
+        // by changes in wakefulness.
+        final long now = SystemClock.uptimeMillis();
+        int dirtyPhase2 = 0;
+        for (;;) {
+            int dirtyPhase1 = mDirty;
+            dirtyPhase2 |= dirtyPhase1;
+            mDirty = 0;
 
-        if ((difference & KEYBOARD_BRIGHT_BIT) != 0) {
-            if ((newState & KEYBOARD_BRIGHT_BIT) == 0) {
-                offMask |= KEYBOARD_BRIGHT_BIT;
-            } else {
-                onMask |= KEYBOARD_BRIGHT_BIT;
+            updateWakeLockSummaryLocked(dirtyPhase1);
+            updateUserActivitySummaryLocked(now, dirtyPhase1);
+            if (!updateWakefulnessLocked(dirtyPhase1)) {
+                break;
             }
         }
 
-        if ((difference & BUTTON_BRIGHT_BIT) != 0) {
-            if ((newState & BUTTON_BRIGHT_BIT) == 0) {
-                offMask |= BUTTON_BRIGHT_BIT;
-            } else {
-                onMask |= BUTTON_BRIGHT_BIT;
-            }
-        }
+        // Phase 2: Update dreams and display power state.
+        updateDreamLocked(dirtyPhase2);
+        updateDisplayPowerStateLocked(dirtyPhase2);
 
-        if ((difference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) {
-            int nominalCurrentValue = -1;
-            // If there was an actual difference in the light state, then
-            // figure out the "ideal" current value based on the previous
-            // state.  Otherwise, this is a change due to the brightness
-            // override, so we want to animate from whatever the current
-            // value is.
-            if ((realDifference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) {
-                switch (oldState & (SCREEN_BRIGHT_BIT|SCREEN_ON_BIT)) {
-                    case SCREEN_BRIGHT_BIT | SCREEN_ON_BIT:
-                        nominalCurrentValue = preferredBrightness;
-                        break;
-                    case SCREEN_ON_BIT:
-                        nominalCurrentValue = mScreenBrightnessDim;
-                        break;
-                    case 0:
-                        nominalCurrentValue = PowerManager.BRIGHTNESS_OFF;
-                        break;
-                    case SCREEN_BRIGHT_BIT:
-                    default:
-                        // not possible
-                        nominalCurrentValue = (int)mScreenBrightnessAnimator.getCurrentBrightness();
-                        break;
-                }
-            }
-            int brightness = preferredBrightness;
-            int steps = ANIM_STEPS;
-            if ((newState & SCREEN_BRIGHT_BIT) == 0) {
-                // dim or turn off backlight, depending on if the screen is on
-                // the scale is because the brightness ramp isn't linear and this biases
-                // it so the later parts take longer.
-                final float scale = 1.5f;
-                float ratio = (((float)mScreenBrightnessDim)/preferredBrightness);
-                if (ratio > 1.0f) ratio = 1.0f;
-                if ((newState & SCREEN_ON_BIT) == 0) {
-                    if ((oldState & SCREEN_BRIGHT_BIT) != 0) {
-                        // was bright
-                        steps = ANIM_STEPS;
-                    } else {
-                        // was dim
-                        steps = (int)(ANIM_STEPS*ratio*scale);
-                    }
-                    brightness = PowerManager.BRIGHTNESS_OFF;
-                } else {
-                    if ((oldState & SCREEN_ON_BIT) != 0) {
-                        // was bright
-                        steps = (int)(ANIM_STEPS*(1.0f-ratio)*scale);
-                    } else {
-                        // was dim
-                        steps = (int)(ANIM_STEPS*ratio);
-                    }
-                    final int stayOnConditions = getStayOnConditionsLocked();
-                    if (stayOnConditions != 0 && mBatteryService.isPowered(stayOnConditions)) {
-                        // If the "stay on while plugged in" option is
-                        // turned on, then the screen will often not
-                        // automatically turn off while plugged in.  To
-                        // still have a sense of when it is inactive, we
-                        // will then count going dim as turning off.
-                        mScreenOffTime = SystemClock.elapsedRealtime();
-                    }
-                    brightness = mScreenBrightnessDim;
-                }
-            }
-            if (mWaitingForFirstLightSensor && (newState & SCREEN_ON_BIT) != 0) {
-                steps = IMMEDIATE_ANIM_STEPS;
-            }
+        // Phase 3: Send notifications, if needed.
+        sendPendingNotificationsLocked();
 
-            long identity = Binder.clearCallingIdentity();
-            try {
-                mBatteryStats.noteScreenBrightness(brightness);
-            } catch (RemoteException e) {
-                // Nothing interesting to do.
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-            if (!mSkippedScreenOn) {
-                int dt = steps * NOMINAL_FRAME_TIME_MS;
-                mScreenBrightnessAnimator.animateTo(brightness, SCREEN_BRIGHT_BIT, dt);
-                if (DEBUG_SCREEN_ON) {
-                    RuntimeException e = new RuntimeException("here");
-                    e.fillInStackTrace();
-                    Slog.i(TAG, "Setting screen brightness: " + brightness, e);
-                }
-            }
-        }
+        // Phase 4: Update suspend blocker.
+        // Because we might release the last suspend blocker here, we need to make sure
+        // we finished everything else first!
+        updateSuspendBlockerLocked();
+    }
 
-        if (DEBUG) {
-            Slog.d(TAG, "offMask=0x" + Integer.toHexString(offMask)
-                    + " dimMask=0x" + Integer.toHexString(dimMask)
-                    + " onMask=0x" + Integer.toHexString(onMask)
-                    + " difference=0x" + Integer.toHexString(difference)
-                    + " realDifference=0x" + Integer.toHexString(realDifference)
-                    + " forceState=0x" + Integer.toHexString(forceState)
-                    );
-        }
-
-        if (offMask != 0) {
-            if (DEBUG) Slog.i(TAG, "Setting brightess off: " + offMask);
-            setLightBrightness(offMask, PowerManager.BRIGHTNESS_OFF);
-        }
-        if (dimMask != 0) {
-            int brightness = mScreenBrightnessDim;
-            if ((newState & BATTERY_LOW_BIT) != 0 &&
-                    brightness > PowerManager.BRIGHTNESS_LOW_BATTERY) {
-                brightness = PowerManager.BRIGHTNESS_LOW_BATTERY;
+    private void sendPendingNotificationsLocked() {
+        if (mDisplayReady) {
+            if (mSendWakeUpFinishedNotificationWhenReady) {
+                mSendWakeUpFinishedNotificationWhenReady = false;
+                mNotifier.onWakeUpFinished();
             }
-            if (DEBUG) Slog.i(TAG, "Setting brightess dim " + brightness + ": " + dimMask);
-            setLightBrightness(dimMask, brightness);
-        }
-        if (onMask != 0) {
-            int brightness = getPreferredBrightness();
-            if ((newState & BATTERY_LOW_BIT) != 0 &&
-                    brightness > PowerManager.BRIGHTNESS_LOW_BATTERY) {
-                brightness = PowerManager.BRIGHTNESS_LOW_BATTERY;
+            if (mSendGoToSleepFinishedNotificationWhenReady) {
+                mSendGoToSleepFinishedNotificationWhenReady = false;
+                mNotifier.onGoToSleepFinished();
             }
-            if (DEBUG) Slog.i(TAG, "Setting brightess on " + brightness + ": " + onMask);
-            setLightBrightness(onMask, brightness);
         }
     }
 
     /**
-     * Note: by design this class does not hold mLocks while calling native methods.
-     * Nor should it. Ever.
+     * Updates the value of mIsPowered.
+     * Sets DIRTY_IS_POWERED if a change occurred.
      */
-    class ScreenBrightnessAnimator extends HandlerThread {
-        static final int ANIMATE_LIGHTS = 10;
-        static final int ANIMATE_POWER_OFF = 11;
-        volatile int startValue;
-        volatile int endValue;
-        volatile int startSensorValue;
-        volatile int endSensorValue;
-        volatile int currentValue;
-        private int currentMask;
-        private int duration;
-        private long startTimeMillis;
-        private final String prefix;
+    private void updateIsPoweredLocked(int dirty) {
+        if ((dirty & DIRTY_BATTERY_STATE) != 0) {
+            boolean wasPowered = mIsPowered;
+            mIsPowered = mBatteryService.isPowered();
 
-        public ScreenBrightnessAnimator(String name, int priority) {
-            super(name, priority);
-            prefix = name;
+            if (wasPowered != mIsPowered) {
+                mDirty |= DIRTY_IS_POWERED;
+
+                // Treat plugging and unplugging the devices as a user activity.
+                // Users find it disconcerting when they plug or unplug the device
+                // and it shuts off right away.
+                // Some devices also wake the device when plugged or unplugged because
+                // they don't have a charging LED.
+                final long now = SystemClock.uptimeMillis();
+                if (mWakeUpWhenPluggedOrUnpluggedConfig) {
+                    wakeUpNoUpdateLocked(now);
+                }
+                userActivityNoUpdateLocked(
+                        now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
+            }
+        }
+    }
+
+    /**
+     * Updates the value of mStayOn.
+     * Sets DIRTY_STAY_ON if a change occurred.
+     */
+    private void updateStayOnLocked(int dirty) {
+        if ((dirty & (DIRTY_BATTERY_STATE | DIRTY_SETTINGS)) != 0) {
+            if (mStayOnWhilePluggedInSetting != 0
+                    && !isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
+                mStayOn = mBatteryService.isPowered(mStayOnWhilePluggedInSetting);
+            } else {
+                mStayOn = false;
+            }
+        }
+    }
+
+    /**
+     * Updates the value of mWakeLockSummary to summarize the state of all active wake locks.
+     * Note that most wake-locks are ignored when the system is asleep.
+     *
+     * This function must have no other side-effects.
+     */
+    private void updateWakeLockSummaryLocked(int dirty) {
+        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_WAKEFULNESS)) != 0) {
+            mWakeLockSummary = 0;
+
+            final int numWakeLocks = mWakeLocks.size();
+            for (int i = 0; i < numWakeLocks; i++) {
+                final WakeLock wakeLock = mWakeLocks.get(i);
+                switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
+                    case PowerManager.PARTIAL_WAKE_LOCK:
+                        mWakeLockSummary |= WAKE_LOCK_CPU;
+                        break;
+                    case PowerManager.FULL_WAKE_LOCK:
+                        if (mWakefulness != WAKEFULNESS_ASLEEP) {
+                            mWakeLockSummary |= WAKE_LOCK_CPU
+                                    | WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
+                        }
+                        break;
+                    case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
+                        if (mWakefulness != WAKEFULNESS_ASLEEP) {
+                            mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT;
+                        }
+                        break;
+                    case PowerManager.SCREEN_DIM_WAKE_LOCK:
+                        if (mWakefulness != WAKEFULNESS_ASLEEP) {
+                            mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_DIM;
+                        }
+                        break;
+                    case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
+                        if (mWakefulness != WAKEFULNESS_ASLEEP) {
+                            mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_PROXIMITY_SCREEN_OFF;
+                        }
+                        break;
+                }
+            }
+
+            if (DEBUG_SPEW) {
+                Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
+                        + wakefulnessToString(mWakefulness)
+                        + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
+            }
+        }
+    }
+
+    /**
+     * Updates the value of mUserActivitySummary to summarize the user requested
+     * state of the system such as whether the screen should be bright or dim.
+     * Note that user activity is ignored when the system is asleep.
+     *
+     * This function must have no other side-effects.
+     */
+    private void updateUserActivitySummaryLocked(long now, int dirty) {
+        // Update the status of the user activity timeout timer.
+        if ((dirty & (DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS | DIRTY_SETTINGS)) != 0) {
+            mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
+
+            long nextTimeout = 0;
+            if (mWakefulness != WAKEFULNESS_ASLEEP) {
+                final int screenOffTimeout = getScreenOffTimeoutLocked();
+                final int screenDimDuration = getScreenDimDurationLocked();
+
+                mUserActivitySummary = 0;
+                if (mLastUserActivityTime >= mLastWakeTime) {
+                    nextTimeout = mLastUserActivityTime
+                            + screenOffTimeout - screenDimDuration;
+                    if (now < nextTimeout) {
+                        mUserActivitySummary |= USER_ACTIVITY_SCREEN_BRIGHT;
+                    } else {
+                        nextTimeout = mLastUserActivityTime + screenOffTimeout;
+                        if (now < nextTimeout) {
+                            mUserActivitySummary |= USER_ACTIVITY_SCREEN_DIM;
+                        }
+                    }
+                }
+                if (mUserActivitySummary == 0
+                        && mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
+                    nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
+                    if (now < nextTimeout
+                            && mDisplayPowerRequest.screenState
+                                    != DisplayPowerRequest.SCREEN_STATE_OFF) {
+                        mUserActivitySummary = mDisplayPowerRequest.screenState
+                                == DisplayPowerRequest.SCREEN_STATE_BRIGHT ?
+                                USER_ACTIVITY_SCREEN_BRIGHT : USER_ACTIVITY_SCREEN_DIM;
+                    }
+                }
+                if (mUserActivitySummary != 0) {
+                    Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
+                    msg.setAsynchronous(true);
+                    mHandler.sendMessageAtTime(msg, nextTimeout);
+                }
+            } else {
+                mUserActivitySummary = 0;
+            }
+
+            if (DEBUG_SPEW) {
+                Slog.d(TAG, "updateUserActivitySummaryLocked: mWakefulness="
+                        + wakefulnessToString(mWakefulness)
+                        + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
+                        + ", nextTimeout=" + TimeUtils.formatUptime(nextTimeout));
+            }
+        }
+    }
+
+    /**
+     * Called when a user activity timeout has occurred.
+     * Simply indicates that something about user activity has changed so that the new
+     * state can be recomputed when the power state is updated.
+     *
+     * This function must have no other side-effects besides setting the dirty
+     * bit and calling update power state.  Wakefulness transitions are handled elsewhere.
+     */
+    private void handleUserActivityTimeout() { // runs on handler thread
+        synchronized (mLock) {
+            if (DEBUG_SPEW) {
+                Slog.d(TAG, "handleUserActivityTimeout");
+            }
+
+            mDirty |= DIRTY_USER_ACTIVITY;
+            updatePowerStateLocked();
+        }
+    }
+
+    private int getScreenOffTimeoutLocked() {
+        int timeout = mScreenOffTimeoutSetting;
+        if (isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) {
+            timeout = Math.min(timeout, mMaximumScreenOffTimeoutFromDeviceAdmin);
+        }
+        return Math.max(timeout, MINIMUM_SCREEN_OFF_TIMEOUT);
+    }
+
+    private int getScreenDimDurationLocked() {
+        return SCREEN_DIM_DURATION;
+    }
+
+    /**
+     * Updates the wakefulness of the device.
+     *
+     * This is the function that decides whether the device should start napping
+     * based on the current wake locks and user activity state.  It may modify mDirty
+     * if the wakefulness changes.
+     *
+     * Returns true if the wakefulness changed and we need to restart power state calculation.
+     */
+    private boolean updateWakefulnessLocked(int dirty) {
+        boolean changed = false;
+        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
+                | DIRTY_WAKEFULNESS | DIRTY_STAY_ON)) != 0) {
+            if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
+                if (DEBUG_SPEW) {
+                    Slog.d(TAG, "updateWakefulnessLocked: Nap time...");
+                }
+                mWakefulness = WAKEFULNESS_NAPPING;
+                mDirty |= DIRTY_WAKEFULNESS;
+                changed = true;
+            }
+        }
+        return changed;
+    }
+
+    // Also used when exiting a dream to determine whether we should go back
+    // to being fully awake or else go to sleep for good.
+    private boolean isItBedTimeYetLocked() {
+        return mBootCompleted && !mStayOn
+                && (mWakeLockSummary
+                        & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) == 0
+                && (mUserActivitySummary
+                        & (USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) == 0;
+    }
+
+    /**
+     * Determines whether to post a message to the sandman to update the dream state.
+     */
+    private void updateDreamLocked(int dirty) {
+        if ((dirty & (DIRTY_WAKEFULNESS | DIRTY_SETTINGS
+                | DIRTY_IS_POWERED | DIRTY_STAY_ON)) != 0) {
+            scheduleSandmanLocked();
+        }
+    }
+
+    private void scheduleSandmanLocked() {
+        if (!mSandmanScheduled) {
+            mSandmanScheduled = true;
+            Message msg = mHandler.obtainMessage(MSG_SANDMAN);
+            msg.setAsynchronous(true);
+            mHandler.sendMessage(msg);
+        }
+    }
+
+    /**
+     * Called when the device enters or exits a napping or dreaming state.
+     *
+     * We do this asynchronously because we must call out of the power manager to start
+     * the dream and we don't want to hold our lock while doing so.  There is a risk that
+     * the device will wake or go to sleep in the meantime so we have to handle that case.
+     */
+    private void handleSandman() { // runs on handler thread
+        // Handle preconditions.
+        boolean startDreaming = false;
+        synchronized (mLock) {
+            mSandmanScheduled = false;
+
+            if (DEBUG_SPEW) {
+                Log.d(TAG, "handleSandman: canDream=" + canDreamLocked()
+                        + ", mWakefulness=" + wakefulnessToString(mWakefulness));
+            }
+
+            if (canDreamLocked() && mWakefulness == WAKEFULNESS_NAPPING) {
+                startDreaming = true;
+            }
+        }
+
+        // Get the dream manager, if needed.
+        if (startDreaming && mDreamManager == null) {
+            mDreamManager = IDreamManager.Stub.asInterface(
+                    ServiceManager.checkService("dreams"));
+            if (mDreamManager == null) {
+                Slog.w(TAG, "Unable to find IDreamManager.");
+            }
+        }
+
+        // Start dreaming if needed.
+        // We only control the dream on the handler thread, so we don't need to worry about
+        // concurrent attempts to start or stop the dream.
+        boolean isDreaming = false;
+        if (mDreamManager != null) {
+            try {
+                isDreaming = mDreamManager.isDreaming();
+                if (startDreaming && !isDreaming) {
+                    Slog.i(TAG, "Entering dreamland.");
+                    mDreamManager.dream();
+                    isDreaming = mDreamManager.isDreaming();
+                    if (!isDreaming) {
+                        Slog.i(TAG, "Could not enter dreamland.  Sleep will be dreamless.");
+                    }
+                }
+            } catch (RemoteException ex) {
+            }
+        }
+
+        // Update dream state.
+        // We might need to stop the dream again if the preconditions changed.
+        boolean continueDreaming = false;
+        synchronized (mLock) {
+            if (isDreaming && canDreamLocked()) {
+                if (mWakefulness == WAKEFULNESS_NAPPING) {
+                    mWakefulness = WAKEFULNESS_DREAMING;
+                    mDirty |= DIRTY_WAKEFULNESS;
+                    updatePowerStateLocked();
+                    continueDreaming = true;
+                } else if (mWakefulness == WAKEFULNESS_DREAMING) {
+                    continueDreaming = true;
+                }
+            }
+            if (!continueDreaming) {
+                handleDreamFinishedLocked();
+            }
+
+            // Allow the sandman to detect when the dream has ended.
+            // FIXME: The DreamManagerService should tell us explicitly.
+            if (mWakefulness == WAKEFULNESS_DREAMING
+                    || mWakefulness == WAKEFULNESS_NAPPING) {
+                if (!mSandmanScheduled) {
+                    mSandmanScheduled = true;
+                    Message msg = mHandler.obtainMessage(MSG_SANDMAN);
+                    msg.setAsynchronous(true);
+                    mHandler.sendMessageDelayed(msg, 1000);
+                }
+            }
+        }
+
+        // Stop dreaming if needed.
+        // It's possible that something else changed to make us need to start the dream again.
+        // If so, then the power manager will have posted another message to the handler
+        // to take care of it later.
+        if (mDreamManager != null) {
+            try {
+                if (!continueDreaming && isDreaming) {
+                    Slog.i(TAG, "Leaving dreamland.");
+                    mDreamManager.awaken();
+                }
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    /**
+     * Returns true if the device is allowed to dream in its current state,
+     * assuming there has been no recent user activity and no wake locks are held.
+     */
+    private boolean canDreamLocked() {
+        return mIsPowered && mDreamsSupportedConfig && mDreamsEnabledSetting;
+    }
+
+    /**
+     * Called when a dream is ending to figure out what to do next.
+     */
+    private void handleDreamFinishedLocked() {
+        if (mWakefulness == WAKEFULNESS_NAPPING
+                || mWakefulness == WAKEFULNESS_DREAMING) {
+            if (isItBedTimeYetLocked()) {
+                goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
+                        PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+                updatePowerStateLocked();
+            } else {
+                wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
+                updatePowerStateLocked();
+            }
+        }
+    }
+
+
+    /**
+     * Updates the display power state asynchronously.
+     * When the update is finished, mDisplayReady will be set to true.  The display
+     * controller posts a message to tell us when the actual display power state
+     * has been updated so we come back here to double-check and finish up.
+     *
+     * This function recalculates the display power state each time.
+     */
+    private void updateDisplayPowerStateLocked(int dirty) {
+        if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
+                | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
+                | DIRTY_SETTINGS)) != 0) {
+            int newScreenState = getDesiredScreenPowerState();
+            if (newScreenState != mDisplayPowerRequest.screenState) {
+                if (newScreenState == DisplayPowerRequest.SCREEN_STATE_OFF
+                        && mDisplayPowerRequest.screenState
+                                != DisplayPowerRequest.SCREEN_STATE_OFF) {
+                    mLastScreenOffEventElapsedRealTime = SystemClock.elapsedRealtime();
+                }
+
+                mDisplayPowerRequest.screenState = newScreenState;
+                nativeSetPowerState(
+                        newScreenState != DisplayPowerRequest.SCREEN_STATE_OFF,
+                        newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT);
+            }
+
+            int screenBrightness = mScreenBrightnessSettingDefault;
+            float screenAutoBrightnessAdjustment = 0.0f;
+            boolean autoBrightness = (mScreenBrightnessModeSetting ==
+                    Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+            if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
+                screenBrightness = mScreenBrightnessOverrideFromWindowManager;
+                autoBrightness = false;
+            } else if (isValidBrightness(mTemporaryScreenBrightnessSettingOverride)) {
+                screenBrightness = mTemporaryScreenBrightnessSettingOverride;
+            } else if (isValidBrightness(mScreenBrightnessSetting)) {
+                screenBrightness = mScreenBrightnessSetting;
+            }
+            if (autoBrightness) {
+                screenBrightness = mScreenBrightnessSettingDefault;
+                if (isValidAutoBrightnessAdjustment(
+                        mTemporaryScreenAutoBrightnessAdjustmentSettingOverride)) {
+                    screenAutoBrightnessAdjustment =
+                            mTemporaryScreenAutoBrightnessAdjustmentSettingOverride;
+                } else if (isValidAutoBrightnessAdjustment(
+                        mScreenAutoBrightnessAdjustmentSetting)) {
+                    screenAutoBrightnessAdjustment = mScreenAutoBrightnessAdjustmentSetting;
+                }
+            }
+            screenBrightness = Math.max(Math.min(screenBrightness,
+                    mScreenBrightnessSettingMaximum), mScreenBrightnessSettingMinimum);
+            screenAutoBrightnessAdjustment = Math.max(Math.min(
+                    screenAutoBrightnessAdjustment, 1.0f), -1.0f);
+            mDisplayPowerRequest.screenBrightness = screenBrightness;
+            mDisplayPowerRequest.screenAutoBrightnessAdjustment =
+                    screenAutoBrightnessAdjustment;
+            mDisplayPowerRequest.useAutoBrightness = autoBrightness;
+
+            mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
+
+            mDisplayReady = mDisplayPowerController.requestPowerState(mDisplayPowerRequest,
+                    mRequestWaitForNegativeProximity);
+            mRequestWaitForNegativeProximity = false;
+
+            if (DEBUG_SPEW) {
+                Slog.d(TAG, "updateScreenStateLocked: displayReady=" + mDisplayReady
+                        + ", newScreenState=" + newScreenState
+                        + ", mWakefulness=" + mWakefulness
+                        + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
+                        + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
+                        + ", mBootCompleted=" + mBootCompleted);
+            }
+        }
+    }
+
+    private static boolean isValidBrightness(int value) {
+        return value >= 0 && value <= 255;
+    }
+
+    private static boolean isValidAutoBrightnessAdjustment(float value) {
+        // Handles NaN by always returning false.
+        return value >= -1.0f && value <= 1.0f;
+    }
+
+    private int getDesiredScreenPowerState() {
+        if (mWakefulness == WAKEFULNESS_ASLEEP) {
+            return DisplayPowerRequest.SCREEN_STATE_OFF;
+        }
+
+        if ((mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0
+                || (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
+                || !mBootCompleted) {
+            return DisplayPowerRequest.SCREEN_STATE_BRIGHT;
+        }
+
+        return DisplayPowerRequest.SCREEN_STATE_DIM;
+    }
+
+    private final DisplayPowerController.Callbacks mDisplayPowerControllerCallbacks =
+            new DisplayPowerController.Callbacks() {
+        @Override
+        public void onStateChanged() {
+            mDirty |= DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED;
+            updatePowerStateLocked();
         }
 
         @Override
-        protected void onLooperPrepared() {
-            mScreenBrightnessHandler = new Handler() {
-                public void handleMessage(Message msg) {
-                    int brightnessMode = (mAutoBrightessEnabled && !mInitialAnimation
-                            ? LightsService.BRIGHTNESS_MODE_SENSOR
-                            : LightsService.BRIGHTNESS_MODE_USER);
-                    if (msg.what == ANIMATE_LIGHTS) {
-                        final int mask = msg.arg1;
-                        int value = msg.arg2;
-                        long tStart = SystemClock.uptimeMillis();
-                        if ((mask & SCREEN_BRIGHT_BIT) != 0) {
-                            if (DEBUG_LIGHT_ANIMATION) Slog.v(TAG, "Set brightness: " + value);
-                            mLcdLight.setBrightness(value, brightnessMode);
-                        }
-                        long elapsed = SystemClock.uptimeMillis() - tStart;
-                        if ((mask & BUTTON_BRIGHT_BIT) != 0) {
-                            mButtonLight.setBrightness(value);
-                        }
-                        if ((mask & KEYBOARD_BRIGHT_BIT) != 0) {
-                            mKeyboardLight.setBrightness(value);
-                        }
+        public void onProximityNegative() {
+            userActivityNoUpdateLocked(SystemClock.uptimeMillis(),
+                    PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
+            updatePowerStateLocked();
+        }
+    };
 
-                        if (elapsed > 100) {
-                            Slog.e(TAG, "Excessive delay setting brightness: " + elapsed
-                                    + "ms, mask=" + mask);
-                        }
+    private boolean shouldUseProximitySensorLocked() {
+        return (mWakeLockSummary & WAKE_LOCK_PROXIMITY_SCREEN_OFF) != 0;
+    }
 
-                        // Throttle brightness updates to frame refresh rate
-                        int delay = elapsed < NOMINAL_FRAME_TIME_MS ? NOMINAL_FRAME_TIME_MS : 1;
-                        synchronized(this) {
-                            currentValue = value;
-                        }
-                        animateInternal(mask, false, delay);
-                    } else if (msg.what == ANIMATE_POWER_OFF) {
-                        int mode = msg.arg1;
-                        nativeStartSurfaceFlingerAnimation(mode);
-                    }
+    /**
+     * Updates the suspend blocker that keeps the CPU alive.
+     *
+     * This function must have no other side-effects.
+     */
+    private void updateSuspendBlockerLocked() {
+        boolean wantCpu = isCpuNeededLocked();
+        if (wantCpu != mHoldingWakeLockSuspendBlocker) {
+            mHoldingWakeLockSuspendBlocker = wantCpu;
+            if (wantCpu) {
+                if (DEBUG) {
+                    Slog.d(TAG, "updateSuspendBlockerLocked: Acquiring suspend blocker.");
                 }
-            };
-            synchronized (this) {
-                mInitComplete = true;
-                notifyAll();
-            }
-        }
-
-        private void animateInternal(int mask, boolean turningOff, int delay) {
-            synchronized (this) {
-                if (currentValue != endValue) {
-                    final long now = SystemClock.elapsedRealtime();
-                    final int elapsed = (int) (now - startTimeMillis);
-                    int newValue;
-                    if (elapsed < duration) {
-                        int delta = endValue - startValue;
-                        newValue = startValue + delta * elapsed / duration;
-                        newValue = Math.max(PowerManager.BRIGHTNESS_OFF, newValue);
-                        newValue = Math.min(PowerManager.BRIGHTNESS_ON, newValue);
-                        // Optimization to delay next step until a change will occur.
-                        if (delay > 0 && newValue == currentValue) {
-                            final int timePerStep = duration / Math.abs(delta);
-                            delay = Math.min(duration - elapsed, timePerStep);
-                            newValue += delta < 0 ? -1 : 1;
-                        }
-                        // adjust the peak sensor value until we get to the target sensor value
-                        delta = endSensorValue - startSensorValue;
-                        mHighestLightSensorValue = startSensorValue + delta * elapsed / duration;
-                    } else {
-                        newValue = endValue;
-                        mHighestLightSensorValue = endSensorValue;
-                        if (endValue > 0) {
-                            mInitialAnimation = false;
-                        }
-                    }
-
-                    if (DEBUG_LIGHT_ANIMATION) {
-                        Slog.v(TAG, "Animating light: " + "start:" + startValue
-                                + ", end:" + endValue + ", elapsed:" + elapsed
-                                + ", duration:" + duration + ", current:" + currentValue
-                                + ", newValue:" + newValue
-                                + ", delay:" + delay
-                                + ", highestSensor:" + mHighestLightSensorValue);
-                    }
-
-                    if (turningOff && !mHeadless && !mAnimateScreenLights) {
-                        int mode = mScreenOffReason == OFF_BECAUSE_OF_PROX_SENSOR
-                                ? 0 : mAnimationSetting;
-                        if (DEBUG_LIGHT_ANIMATION) {
-                            Slog.v(TAG, "Doing power-off anim, mode=" + mode);
-                        }
-                        mScreenBrightnessHandler.obtainMessage(ANIMATE_POWER_OFF, mode, 0)
-                                .sendToTarget();
-                    }
-                    mScreenBrightnessHandler.removeMessages(
-                            ScreenBrightnessAnimator.ANIMATE_LIGHTS);
-                    Message msg = mScreenBrightnessHandler
-                            .obtainMessage(ANIMATE_LIGHTS, mask, newValue);
-                    mScreenBrightnessHandler.sendMessageDelayed(msg, delay);
-                }
-            }
-        }
-
-        public void dump(PrintWriter pw, String string) {
-            pw.println(string);
-            pw.println("  animating: " + "start:" + startValue + ", end:" + endValue
-                    + ", duration:" + duration + ", current:" + currentValue);
-            pw.println("  startSensorValue:" + startSensorValue
-                    + " endSensorValue:" + endSensorValue);
-            pw.println("  startTimeMillis:" + startTimeMillis
-                    + " now:" + SystemClock.elapsedRealtime());
-            pw.println("  currentMask:" + dumpPowerState(currentMask));
-        }
-
-        public void animateTo(int target, int mask, int animationDuration) {
-            animateTo(target, mHighestLightSensorValue, mask, animationDuration);
-        }
-
-        public void animateTo(int target, int sensorTarget, int mask, int animationDuration) {
-            synchronized(this) {
-                if ((mask & SCREEN_BRIGHT_BIT) == 0) {
-                    // We only animate keyboard and button when passed in with SCREEN_BRIGHT_BIT.
-                    if ((mask & BUTTON_BRIGHT_BIT) != 0) {
-                        mButtonLight.setBrightness(target);
-                    }
-                    if ((mask & KEYBOARD_BRIGHT_BIT) != 0) {
-                        mKeyboardLight.setBrightness(target);
-                    }
-                    return;
-                }
-                if (isAnimating() && (mask ^ currentMask) != 0) {
-                    // current animation is unrelated to new animation, jump to final values
-                    cancelAnimation();
-                }
-                if (mInitialAnimation) {
-                    // jump to final value in one step the first time the brightness is set
-                    animationDuration = 0;
-                    if (target > 0) {
-                        mInitialAnimation = false;
-                    }
-                }
-                startValue = currentValue;
-                endValue = target;
-                startSensorValue = mHighestLightSensorValue;
-                endSensorValue = sensorTarget;
-                currentMask = mask;
-                duration = (int) (mWindowScaleAnimation * animationDuration);
-                startTimeMillis = SystemClock.elapsedRealtime();
-
-                if (DEBUG_LIGHT_ANIMATION) {
-                    Slog.v(TAG, "animateTo(target=" + target
-                            + ", sensor=" + sensorTarget
-                            + ", mask=" + mask
-                            + ", duration=" + animationDuration +")"
-                            + ", currentValue=" + currentValue
-                            + ", startTime=" + startTimeMillis);
-                }
-
-                if (target != currentValue) {
-                    final boolean doScreenAnim = (mask & (SCREEN_BRIGHT_BIT | SCREEN_ON_BIT)) != 0;
-                    final boolean turningOff = endValue == PowerManager.BRIGHTNESS_OFF;
-                    if (turningOff && doScreenAnim) {
-                        // Cancel all pending animations since we're turning off
-                        mScreenBrightnessHandler.removeCallbacksAndMessages(null);
-                        screenOffFinishedAnimatingLocked(mScreenOffReason);
-                        duration = 200; // TODO: how long should this be?
-                    }
-                    if (doScreenAnim) {
-                        animateInternal(mask, turningOff, 0);
-                    }
-                    // TODO: Handle keyboard light animation when we have devices that support it
-                }
-            }
-        }
-
-        public int getCurrentBrightness() {
-            synchronized (this) {
-                return currentValue;
-            }
-        }
-
-        public boolean isAnimating() {
-            synchronized (this) {
-                return currentValue != endValue;
-            }
-        }
-
-        public void cancelAnimation() {
-            animateTo(endValue, currentMask, 0);
-        }
-    }
-
-    private void setLightBrightness(int mask, int value) {
-        mScreenBrightnessAnimator.animateTo(value, mask, 0);
-    }
-
-    private int getPreferredBrightness() {
-        int brightness = mScreenBrightnessSetting;
-        if (mScreenBrightnessOverride >= 0) {
-            brightness = mScreenBrightnessOverride;
-        } else if (mLightSensorScreenBrightness >= 0 && mUseSoftwareAutoBrightness
-                && mAutoBrightessEnabled) {
-            brightness = mLightSensorScreenBrightness;
-        }
-         // Don't let applications turn the screen all the way off
-        return Math.max(brightness, mScreenBrightnessDim);
-    }
-
-    private int applyButtonState(int state) {
-        int brightness = -1;
-        if ((state & BATTERY_LOW_BIT) != 0) {
-            // do not override brightness if the battery is low
-            return state;
-        }
-        if (mButtonBrightnessOverride >= 0) {
-            brightness = mButtonBrightnessOverride;
-        } else if (mLightSensorButtonBrightness >= 0 && mUseSoftwareAutoBrightness) {
-            brightness = mLightSensorButtonBrightness;
-        }
-        if (brightness > 0) {
-            return state | BUTTON_BRIGHT_BIT;
-        } else if (brightness == 0) {
-            return state & ~BUTTON_BRIGHT_BIT;
-        } else {
-            return state;
-        }
-    }
-
-    private int applyKeyboardState(int state) {
-        int brightness = -1;
-        if ((state & BATTERY_LOW_BIT) != 0) {
-            // do not override brightness if the battery is low
-            return state;
-        }
-        if (!mKeyboardVisible) {
-            brightness = 0;
-        } else if (mButtonBrightnessOverride >= 0) {
-            brightness = mButtonBrightnessOverride;
-        } else if (mLightSensorKeyboardBrightness >= 0 && mUseSoftwareAutoBrightness) {
-            brightness =  mLightSensorKeyboardBrightness;
-        }
-        if (brightness > 0) {
-            return state | KEYBOARD_BRIGHT_BIT;
-        } else if (brightness == 0) {
-            return state & ~KEYBOARD_BRIGHT_BIT;
-        } else {
-            return state;
-        }
-    }
-
-    public boolean isScreenOn() {
-        synchronized (mLocks) {
-            return (mPowerState & SCREEN_ON_BIT) != 0;
-        }
-    }
-
-    boolean isScreenBright() {
-        synchronized (mLocks) {
-            return (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT;
-        }
-    }
-
-    private boolean isScreenTurningOffLocked() {
-        return (mScreenBrightnessAnimator.isAnimating()
-                && mScreenBrightnessAnimator.endValue == PowerManager.BRIGHTNESS_OFF
-                && (mScreenBrightnessAnimator.currentMask & SCREEN_BRIGHT_BIT) != 0);
-    }
-
-    private boolean shouldLog(long time) {
-        synchronized (mLocks) {
-            if (time > (mWarningSpewThrottleTime + (60*60*1000))) {
-                mWarningSpewThrottleTime = time;
-                mWarningSpewThrottleCount = 0;
-                return true;
-            } else if (mWarningSpewThrottleCount < 30) {
-                mWarningSpewThrottleCount++;
-                return true;
+                mWakeLockSuspendBlocker.acquire();
             } else {
-                return false;
-            }
-        }
-    }
-
-    private void forceUserActivityLocked() {
-        if (isScreenTurningOffLocked()) {
-            // cancel animation so userActivity will succeed
-            mScreenBrightnessAnimator.cancelAnimation();
-        }
-        boolean savedActivityAllowed = mUserActivityAllowed;
-        mUserActivityAllowed = true;
-        userActivity(SystemClock.uptimeMillis(), false);
-        mUserActivityAllowed = savedActivityAllowed;
-    }
-
-    public void userActivityWithForce(long time, boolean noChangeLights, boolean force) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-        userActivity(time, -1, noChangeLights, PowerManager.USER_ACTIVITY_EVENT_OTHER, force, false);
-    }
-
-    public void userActivity(long time, boolean noChangeLights) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
-                != PackageManager.PERMISSION_GRANTED) {
-            if (shouldLog(time)) {
-                Slog.w(TAG, "Caller does not have DEVICE_POWER permission.  pid="
-                        + Binder.getCallingPid() + " uid=" + Binder.getCallingUid());
-            }
-            return;
-        }
-
-        userActivity(time, -1, noChangeLights, PowerManager.USER_ACTIVITY_EVENT_OTHER, false, false);
-    }
-
-    public void userActivity(long time, boolean noChangeLights, int eventType) {
-        userActivity(time, -1, noChangeLights, eventType, false, false);
-    }
-
-    public void userActivity(long time, boolean noChangeLights, int eventType, boolean force) {
-        userActivity(time, -1, noChangeLights, eventType, force, false);
-    }
-
-    /*
-     * Reset the user activity timeout to now + timeout.  This overrides whatever else is going
-     * on with user activity.  Don't use this function.
-     */
-    public void clearUserActivityTimeout(long now, long timeout) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-        Slog.i(TAG, "clearUserActivity for " + timeout + "ms from now");
-        userActivity(now, timeout, false, PowerManager.USER_ACTIVITY_EVENT_OTHER, false, false);
-    }
-
-    private void userActivity(long time, long timeoutOverride, boolean noChangeLights,
-            int eventType, boolean force, boolean ignoreIfScreenOff) {
-
-        if (((mPokey & POKE_LOCK_IGNORE_TOUCH_EVENTS) != 0) && (eventType == PowerManager.USER_ACTIVITY_EVENT_TOUCH)) {
-            if (false) {
-                Slog.d(TAG, "dropping touch mPokey=0x" + Integer.toHexString(mPokey));
-            }
-            return;
-        }
-
-        synchronized (mLocks) {
-            if (DEBUG) {
-                Slog.d(TAG, "userActivity mLastEventTime=" + mLastEventTime + " time=" + time
-                        + " mUserActivityAllowed=" + mUserActivityAllowed
-                        + " mUserState=0x" + Integer.toHexString(mUserState)
-                        + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState)
-                        + " mProximitySensorActive=" + mProximitySensorActive
-                        + " timeoutOverride=" + timeoutOverride
-                        + " force=" + force);
-            }
-            // ignore user activity if we are in the process of turning off the screen
-            if (isScreenTurningOffLocked()) {
-                Slog.d(TAG, "ignoring user activity while turning off screen");
-                return;
-            }
-            // ignore if the caller doesn't want this to allow the screen to turn
-            // on, and the screen is currently off.
-            if (ignoreIfScreenOff && (mPowerState & SCREEN_ON_BIT) == 0) {
-                return;
-            }
-            // Disable proximity sensor if if user presses power key while we are in the
-            // "waiting for proximity sensor to go negative" state.
-            if (mProximitySensorActive && mProximityWakeLockCount == 0) {
-                mProximitySensorActive = false;
-            }
-            if (mLastEventTime <= time || force) {
-                mLastEventTime = time;
-                if ((mUserActivityAllowed && !mProximitySensorActive) || force) {
-                    // Only turn on button backlights if a button was pressed
-                    // and auto brightness is disabled
-                    if (eventType == PowerManager.USER_ACTIVITY_EVENT_BUTTON && !mUseSoftwareAutoBrightness) {
-                        mUserState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
-                    } else {
-                        // don't clear button/keyboard backlights when the screen is touched.
-                        mUserState |= SCREEN_BRIGHT;
-                    }
-
-                    int uid = Binder.getCallingUid();
-                    long ident = Binder.clearCallingIdentity();
-                    try {
-                        mBatteryStats.noteUserActivity(uid, eventType);
-                    } catch (RemoteException e) {
-                        // Ignore
-                    } finally {
-                        Binder.restoreCallingIdentity(ident);
-                    }
-
-                    mWakeLockState = mLocks.reactivateScreenLocksLocked();
-                    setPowerState(mUserState | mWakeLockState, noChangeLights,
-                            WindowManagerPolicy.OFF_BECAUSE_OF_USER);
-                    setTimeoutLocked(time, timeoutOverride, SCREEN_BRIGHT);
+                if (DEBUG) {
+                    Slog.d(TAG, "updateSuspendBlockerLocked: Releasing suspend blocker.");
                 }
+                mWakeLockSuspendBlocker.release();
             }
         }
-
-        if (mPolicy != null) {
-            mPolicy.userActivity();
-        }
     }
 
-    private int getAutoBrightnessValue(int sensorValue, int[] values) {
+    private boolean isCpuNeededLocked() {
+        return !mBootCompleted
+                || mWakeLockSummary != 0
+                || mUserActivitySummary != 0
+                || mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF
+                || !mDisplayReady;
+    }
+
+    @Override // Binder call
+    public boolean isScreenOn() {
+        final long ident = Binder.clearCallingIdentity();
         try {
-            int i;
-            for (i = 0; i < mAutoBrightnessLevels.length; i++) {
-                if (sensorValue < mAutoBrightnessLevels[i]) {
-                    break;
-                }
-            }
-            // This is the range of brightness values that we can use.
-            final int minval = values[0];
-            final int maxval = values[mAutoBrightnessLevels.length];
-            // This is the range we will be scaling.  We put some padding
-            // at the low and high end to give the adjustment a little better
-            // impact on the actual observed value.
-            final int range = (maxval-minval) + LIGHT_SENSOR_RANGE_EXPANSION;
-            // This is the desired brightness value from 0.0 to 1.0.
-            float valf = ((values[i]-minval+(LIGHT_SENSOR_RANGE_EXPANSION/2))/(float)range);
-            // Apply a scaling to the value based on the adjustment.
-            if (mLightSensorAdjustSetting > 0 && mLightSensorAdjustSetting <= 1) {
-                float adj = (float)Math.sqrt(1.0f-mLightSensorAdjustSetting);
-                if (adj <= .00001) {
-                    valf = 1;
-                } else {
-                    valf /= adj;
-                }
-            } else if (mLightSensorAdjustSetting < 0 && mLightSensorAdjustSetting >= -1) {
-                float adj = (float)Math.sqrt(1.0f+mLightSensorAdjustSetting);
-                valf *= adj;
-            }
-            // Apply an additional offset to the value based on the adjustment.
-            valf += mLightSensorAdjustSetting/LIGHT_SENSOR_OFFSET_SCALE;
-            // Convert the 0.0-1.0 value back to a brightness integer.
-            int val = (int)((valf*range)+minval) - (LIGHT_SENSOR_RANGE_EXPANSION/2);
-            if (val < minval) val = minval;
-            else if (val > maxval) val = maxval;
-            return val;
-        } catch (Exception e) {
-            // guard against null pointer or index out of bounds errors
-            Slog.e(TAG, "Values array must be non-empty and must be one element longer than "
-                    + "the auto-brightness levels array.  Check config.xml.", e);
-            return 255;
+            return isScreenOnInternal();
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
-    private Runnable mProximityTask = new Runnable() {
-        public void run() {
-            synchronized (mLocks) {
-                if (mProximityPendingValue != -1) {
-                    proximityChangedLocked(mProximityPendingValue == 1);
-                    mProximityPendingValue = -1;
-                }
-                if (mProximityPartialLock.isHeld()) {
-                    mProximityPartialLock.release();
-                }
-            }
-        }
-    };
-
-    private Runnable mAutoBrightnessTask = new Runnable() {
-        public void run() {
-            synchronized (mLocks) {
-                if (mLightSensorPendingDecrease || mLightSensorPendingIncrease) {
-                    int value = (int)mLightSensorPendingValue;
-                    mLightSensorPendingDecrease = false;
-                    mLightSensorPendingIncrease = false;
-                    lightSensorChangedLocked(value, false);
-                }
-            }
-        }
-    };
-
-    /** used to prevent lightsensor changes while turning on. */
-    private boolean mInitialAnimation = true;
-
-    private void dockStateChanged(int state) {
-        synchronized (mLocks) {
-            mIsDocked = (state != Intent.EXTRA_DOCK_STATE_UNDOCKED);
-            if (mIsDocked) {
-                // allow brightness to decrease when docked
-                mHighestLightSensorValue = -1;
-            }
-            if ((mPowerState & SCREEN_ON_BIT) != 0) {
-                // force lights recalculation
-                int value = (int)mLightSensorValue;
-                mLightSensorValue = -1;
-                lightSensorChangedLocked(value, false);
-            }
+    private boolean isScreenOnInternal() {
+        synchronized (mLock) {
+            return !mSystemReady
+                    || mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF;
         }
     }
 
-    private void lightSensorChangedLocked(int value, boolean immediate) {
-        if (DEBUG_LIGHT_SENSOR) {
-            Slog.d(TAG, "lightSensorChangedLocked value=" + value + " immediate=" + immediate);
-        }
-
-        // Don't do anything if the screen is off.
-        if ((mPowerState & SCREEN_ON_BIT) == 0) {
-            if (DEBUG_LIGHT_SENSOR) {
-                Slog.d(TAG, "dropping lightSensorChangedLocked because screen is off");
-            }
-            return;
-        }
-
-        if (mLightSensorValue != value) {
-            mLightSensorValue = value;
-            if ((mPowerState & BATTERY_LOW_BIT) == 0) {
-                // use maximum light sensor value seen since screen went on for LCD to avoid flicker
-                // we only do this if we are undocked, since lighting should be stable when
-                // stationary in a dock.
-                int lcdValue = getAutoBrightnessValue(value, mLcdBacklightValues);
-                int buttonValue = getAutoBrightnessValue(value, mButtonBacklightValues);
-                int keyboardValue;
-                if (mKeyboardVisible) {
-                    keyboardValue = getAutoBrightnessValue(value, mKeyboardBacklightValues);
-                } else {
-                    keyboardValue = 0;
-                }
-                mLightSensorScreenBrightness = lcdValue;
-                mLightSensorButtonBrightness = buttonValue;
-                mLightSensorKeyboardBrightness = keyboardValue;
-
-                if (DEBUG_LIGHT_SENSOR) {
-                    Slog.d(TAG, "lcdValue " + lcdValue);
-                    Slog.d(TAG, "buttonValue " + buttonValue);
-                    Slog.d(TAG, "keyboardValue " + keyboardValue);
-                }
-
-                if (mAutoBrightessEnabled && mScreenBrightnessOverride < 0) {
-                    if (!mSkippedScreenOn && !mInitialAnimation) {
-                        final int steps;
-                        if (immediate) {
-                            steps = IMMEDIATE_ANIM_STEPS;
-                        } else {
-                            synchronized (mScreenBrightnessAnimator) {
-                                if (mScreenBrightnessAnimator.currentValue <= lcdValue) {
-                                    steps = AUTOBRIGHTNESS_ANIM_STEPS;
-                                } else {
-                                    steps = AUTODIMNESS_ANIM_STEPS;
-                                }
-                            }
-                        }
-                        mScreenBrightnessAnimator.animateTo(lcdValue, value,
-                                SCREEN_BRIGHT_BIT, steps * NOMINAL_FRAME_TIME_MS);
-                    }
-                }
-                if (mButtonBrightnessOverride < 0) {
-                    mButtonLight.setBrightness(buttonValue);
-                }
-                if (mButtonBrightnessOverride < 0 || !mKeyboardVisible) {
-                    mKeyboardLight.setBrightness(keyboardValue);
-                }
-            }
-        }
+    private void handleBatteryStateChangedLocked() {
+        mDirty |= DIRTY_BATTERY_STATE;
+        updatePowerStateLocked();
     }
 
-    /**
-     * The user requested that we go to sleep (probably with the power button).
-     * This overrides all wake locks that are held.
-     */
-    public void goToSleep(long time)
-    {
-        goToSleepWithReason(time, WindowManagerPolicy.OFF_BECAUSE_OF_USER);
+    private void handleBootCompletedLocked() {
+        final long now = SystemClock.uptimeMillis();
+        mBootCompleted = true;
+        mDirty |= DIRTY_BOOT_COMPLETED;
+        userActivityNoUpdateLocked(
+                now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
+        updatePowerStateLocked();
     }
 
-    /**
-     * The user requested that we go to sleep (probably with the power button).
-     * This overrides all wake locks that are held.
-     */
-    public void goToSleepWithReason(long time, int reason)
-    {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-        synchronized (mLocks) {
-            goToSleepLocked(time, reason);
-        }
+    private void handleDockStateChangedLocked(int dockState) {
+        // TODO
     }
 
     /**
      * Reboot the device immediately, passing 'reason' (may be null)
      * to the underlying __reboot system call.  Should not return.
      */
-    public void reboot(String reason)
-    {
+    @Override // Binder call
+    public void reboot(String reason) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
 
-        if (mHandler == null || !ActivityManagerNative.isSystemReady()) {
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            rebootInternal(reason);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private void rebootInternal(final String reason) {
+        if (mHandler == null || !mSystemReady) {
             throw new IllegalStateException("Too early to call reboot()");
         }
 
-        final String finalReason = reason;
         Runnable runnable = new Runnable() {
             public void run() {
                 synchronized (this) {
-                    ShutdownThread.reboot(mContext, finalReason, false);
+                    ShutdownThread.reboot(mContext, reason, false);
                 }
-
             }
         };
+
         // ShutdownThread must run on a looper capable of displaying the UI.
-        mHandler.post(runnable);
+        Message msg = Message.obtain(mHandler, runnable);
+        msg.setAsynchronous(true);
+        mHandler.sendMessage(msg);
 
         // PowerManager.reboot() is documented not to return so just wait for the inevitable.
         synchronized (runnable) {
@@ -2798,11 +1500,23 @@
      * Crash the runtime (causing a complete restart of the Android framework).
      * Requires REBOOT permission.  Mostly for testing.  Should not return.
      */
-    public void crash(final String message)
-    {
+    @Override // Binder call
+    public void crash(String message) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            crashInternal(message);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private void crashInternal(final String message) {
         Thread t = new Thread("PowerManagerService.crash()") {
-            public void run() { throw new RuntimeException(message); }
+            public void run() {
+                throw new RuntimeException(message);
+            }
         };
         try {
             t.start();
@@ -2812,581 +1526,575 @@
         }
     }
 
-    private void goToSleepLocked(long time, int reason) {
-        if (DEBUG) {
-            Exception ex = new Exception();
-            ex.fillInStackTrace();
-            Slog.d(TAG, "goToSleep mLastEventTime=" + mLastEventTime + " time=" + time
-                    + " reason=" + reason, ex);
-        }
-
-        if (mLastEventTime <= time) {
-            mLastEventTime = time;
-            // cancel all of the wake locks
-            mWakeLockState = SCREEN_OFF;
-            int N = mLocks.size();
-            int numCleared = 0;
-            boolean proxLock = false;
-            for (int i=0; i<N; i++) {
-                WakeLock wl = mLocks.get(i);
-                if (isScreenLock(wl.flags)) {
-                    if (((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)
-                            && reason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) {
-                        proxLock = true;
-                    } else {
-                        mLocks.get(i).activated = false;
-                        numCleared++;
-                    }
-                }
-            }
-            if (!proxLock) {
-                mProxIgnoredBecauseScreenTurnedOff = true;
-                if (DEBUG_PROXIMITY_SENSOR) {
-                    Slog.d(TAG, "setting mProxIgnoredBecauseScreenTurnedOff");
-                }
-            }
-            EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numCleared);
-            mStillNeedSleepNotification = true;
-            mUserState = SCREEN_OFF;
-            setPowerState(SCREEN_OFF, false, reason);
-            cancelTimerLocked();
-        }
+    @Override // Binder call
+    public void clearUserActivityTimeout(long now, long timeout) {
+        // TODO Auto-generated method stub
+        // Only used by phone app, delete this
     }
 
-    public long timeSinceScreenOn() {
-        synchronized (mLocks) {
-            if ((mPowerState & SCREEN_ON_BIT) != 0) {
-                return 0;
-            }
-            return SystemClock.elapsedRealtime() - mScreenOffTime;
-        }
-    }
-
-    public void setKeyboardVisibility(boolean visible) {
-        synchronized (mLocks) {
-            if (DEBUG) {
-                Slog.d(TAG, "setKeyboardVisibility: " + visible);
-            }
-            if (mKeyboardVisible != visible) {
-                mKeyboardVisible = visible;
-                // don't signal user activity if the screen is off; other code
-                // will take care of turning on due to a true change to the lid
-                // switch and synchronized with the lock screen.
-                if ((mPowerState & SCREEN_ON_BIT) != 0) {
-                    if (mUseSoftwareAutoBrightness) {
-                        // force recompute of backlight values
-                        if (mLightSensorValue >= 0) {
-                            int value = (int)mLightSensorValue;
-                            mLightSensorValue = -1;
-                            lightSensorChangedLocked(value, false);
-                        }
-                    }
-                    userActivity(SystemClock.uptimeMillis(), false, PowerManager.USER_ACTIVITY_EVENT_BUTTON, true);
-                }
-            }
-        }
+    @Override // Binder call
+    public void setPokeLock(int pokey, IBinder lock, String tag) {
+        // TODO Auto-generated method stub
+        // Only used by phone app, delete this
     }
 
     /**
-     * When the keyguard is up, it manages the power state, and userActivity doesn't do anything.
-     * When disabling user activity we also reset user power state so the keyguard can reset its
-     * short screen timeout when keyguard is unhidden.
+     * Set the setting that determines whether the device stays on when plugged in.
+     * The argument is a bit string, with each bit specifying a power source that,
+     * when the device is connected to that source, causes the device to stay on.
+     * See {@link android.os.BatteryManager} for the list of power sources that
+     * can be specified. Current values include {@link android.os.BatteryManager#BATTERY_PLUGGED_AC}
+     * and {@link android.os.BatteryManager#BATTERY_PLUGGED_USB}
+     *
+     * Used by "adb shell svc power stayon ..."
+     *
+     * @param val an {@code int} containing the bits that specify which power sources
+     * should cause the device to stay on.
      */
-    public void enableUserActivity(boolean enabled) {
-        if (DEBUG) {
-            Slog.d(TAG, "enableUserActivity " + enabled);
-        }
-        synchronized (mLocks) {
-            mUserActivityAllowed = enabled;
-            if (!enabled) {
-                // cancel timeout and clear mUserState so the keyguard can set a short timeout
-                setTimeoutLocked(SystemClock.uptimeMillis(), 0);
-            }
+    @Override // Binder call
+    public void setStayOnSetting(int val) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS, null);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            setStayOnSettingInternal(val);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
-    private void setScreenBrightnessMode(int mode) {
-        synchronized (mLocks) {
-            boolean enabled = (mode == SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
-            if (mUseSoftwareAutoBrightness && mAutoBrightessEnabled != enabled) {
-                mAutoBrightessEnabled = enabled;
-                // This will get us a new value
-                enableLightSensorLocked(mAutoBrightessEnabled && isScreenOn());
-            }
-        }
-    }
-
-    /** Sets the screen off timeouts:
-     *      mKeylightDelay
-     *      mDimDelay
-     *      mScreenOffDelay
-     * */
-    private void setScreenOffTimeoutsLocked() {
-        if ((mPokey & POKE_LOCK_SHORT_TIMEOUT) != 0) {
-            mKeylightDelay = mShortKeylightDelay;  // Configurable via secure settings
-            mDimDelay = -1;
-            mScreenOffDelay = 0;
-        } else if ((mPokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0) {
-            mKeylightDelay = MEDIUM_KEYLIGHT_DELAY;
-            mDimDelay = -1;
-            mScreenOffDelay = 0;
-        } else {
-            int totalDelay = mScreenOffTimeoutSetting;
-            if (totalDelay > mMaximumScreenOffTimeout) {
-                totalDelay = mMaximumScreenOffTimeout;
-            }
-            mKeylightDelay = LONG_KEYLIGHT_DELAY;
-            if (totalDelay < 0) {
-                // negative number means stay on as long as possible.
-                mScreenOffDelay = mMaximumScreenOffTimeout;
-            } else if (mKeylightDelay < totalDelay) {
-                // subtract the time that the keylight delay. This will give us the
-                // remainder of the time that we need to sleep to get the accurate
-                // screen off timeout.
-                mScreenOffDelay = totalDelay - mKeylightDelay;
-            } else {
-                mScreenOffDelay = 0;
-            }
-            if (mDimScreen && totalDelay >= (LONG_KEYLIGHT_DELAY + LONG_DIM_TIME)) {
-                mDimDelay = mScreenOffDelay - LONG_DIM_TIME;
-                mScreenOffDelay = LONG_DIM_TIME;
-            } else {
-                mDimDelay = -1;
-            }
-        }
-        if (DEBUG) {
-            Slog.d(TAG, "setScreenOffTimeouts mKeylightDelay=" + mKeylightDelay
-                    + " mDimDelay=" + mDimDelay + " mScreenOffDelay=" + mScreenOffDelay
-                    + " mDimScreen=" + mDimScreen);
-        }
+    private void setStayOnSettingInternal(int val) {
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.STAY_ON_WHILE_PLUGGED_IN, val);
     }
 
     /**
-     * Refreshes cached secure settings.  Called once on startup, and
-     * on subsequent changes to secure settings.
+     * Used by device administration to set the maximum screen off timeout.
+     *
+     * This method must only be called by the device administration policy manager.
      */
-    private void updateSettingsValues() {
-        mShortKeylightDelay = Settings.Secure.getInt(
-                mContext.getContentResolver(),
-                Settings.Secure.SHORT_KEYLIGHT_DELAY_MS,
-                SHORT_KEYLIGHT_DELAY_DEFAULT);
-        // Slog.i(TAG, "updateSettingsValues(): mShortKeylightDelay now " + mShortKeylightDelay);
-    }
-
-    private class LockList extends ArrayList<WakeLock>
-    {
-        void addLock(WakeLock wl)
-        {
-            int index = getIndex(wl.binder);
-            if (index < 0) {
-                this.add(wl);
-            }
-        }
-
-        WakeLock removeLock(IBinder binder)
-        {
-            int index = getIndex(binder);
-            if (index >= 0) {
-                return this.remove(index);
-            } else {
-                return null;
-            }
-        }
-
-        int getIndex(IBinder binder)
-        {
-            int N = this.size();
-            for (int i=0; i<N; i++) {
-                if (this.get(i).binder == binder) {
-                    return i;
-                }
-            }
-            return -1;
-        }
-
-        int gatherState()
-        {
-            int result = 0;
-            int N = this.size();
-            for (int i=0; i<N; i++) {
-                WakeLock wl = this.get(i);
-                if (wl.activated) {
-                    if (isScreenLock(wl.flags)) {
-                        result |= wl.minState;
-                    }
-                }
-            }
-            return result;
-        }
-
-        int reactivateScreenLocksLocked()
-        {
-            int result = 0;
-            int N = this.size();
-            for (int i=0; i<N; i++) {
-                WakeLock wl = this.get(i);
-                if (isScreenLock(wl.flags)) {
-                    wl.activated = true;
-                    result |= wl.minState;
-                }
-            }
-            if (DEBUG_PROXIMITY_SENSOR) {
-                Slog.d(TAG, "reactivateScreenLocksLocked mProxIgnoredBecauseScreenTurnedOff="
-                        + mProxIgnoredBecauseScreenTurnedOff);
-            }
-            mProxIgnoredBecauseScreenTurnedOff = false;
-            return result;
+    @Override // Binder call
+    public void setMaximumScreenOffTimeoutFromDeviceAdmin(int timeMs) {
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            setMaximumScreenOffTimeoutFromDeviceAdminInternal(timeMs);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
-    public void setPolicy(WindowManagerPolicy p) {
-        synchronized (mLocks) {
-            mPolicy = p;
-            mLocks.notifyAll();
+    private void setMaximumScreenOffTimeoutFromDeviceAdminInternal(int timeMs) {
+        synchronized (mLock) {
+            mMaximumScreenOffTimeoutFromDeviceAdmin = timeMs;
+            mDirty |= DIRTY_SETTINGS;
+            updatePowerStateLocked();
         }
     }
 
-    WindowManagerPolicy getPolicyLocked() {
-        while (mPolicy == null || !mDoneBooting) {
-            try {
-                mLocks.wait();
-            } catch (InterruptedException e) {
-                // Ignore
-            }
-        }
-        return mPolicy;
+    private boolean isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked() {
+        return mMaximumScreenOffTimeoutFromDeviceAdmin >= 0
+                && mMaximumScreenOffTimeoutFromDeviceAdmin < Integer.MAX_VALUE;
     }
 
-    public void systemReady() {
-        mSensorManager = new SystemSensorManager(mHandlerThread.getLooper());
-        mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
-        // don't bother with the light sensor if auto brightness is handled in hardware
-        if (mUseSoftwareAutoBrightness) {
-            mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
-        }
-
-        // wait until sensors are enabled before turning on screen.
-        // some devices will not activate the light sensor properly on boot
-        // unless we do this.
-        if (mUseSoftwareAutoBrightness) {
-            // turn the screen on
-            setPowerState(SCREEN_BRIGHT);
-        } else {
-            // turn everything on
-            setPowerState(ALL_BRIGHT);
-        }
-
-        synchronized (mLocks) {
-            Slog.d(TAG, "system ready!");
-            mDoneBooting = true;
-
-            enableLightSensorLocked(mUseSoftwareAutoBrightness && mAutoBrightessEnabled);
-
-            long identity = Binder.clearCallingIdentity();
-            try {
-                mBatteryStats.noteScreenBrightness(getPreferredBrightness());
-                mBatteryStats.noteScreenOn();
-            } catch (RemoteException e) {
-                // Nothing interesting to do.
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
+    @Override // Binder call
+    public void preventScreenOn(boolean prevent) {
+        // TODO Auto-generated method stub
+        // Only used by phone app, delete this
     }
 
-    void bootCompleted() {
-        Slog.d(TAG, "bootCompleted");
-        synchronized (mLocks) {
-            mBootCompleted = true;
-            userActivity(SystemClock.uptimeMillis(), false, PowerManager.USER_ACTIVITY_EVENT_BUTTON, true);
-            updateWakeLockLocked();
-            mLocks.notifyAll();
-        }
-    }
-
-    // for watchdog
-    public void monitor() {
-        synchronized (mLocks) { }
-    }
-
-    public int getSupportedWakeLockFlags() {
-        int result = PowerManager.PARTIAL_WAKE_LOCK
-                   | PowerManager.FULL_WAKE_LOCK
-                   | PowerManager.SCREEN_DIM_WAKE_LOCK;
-
-        if (mProximitySensor != null) {
-            result |= PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK;
-        }
-
-        return result;
-    }
-
-    public void setBacklightBrightness(int brightness) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-        // Don't let applications turn the screen all the way off
-        synchronized (mLocks) {
-            brightness = Math.max(brightness, mScreenBrightnessDim);
-            mLcdLight.setBrightness(brightness);
-            mKeyboardLight.setBrightness(mKeyboardVisible ? brightness : 0);
-            mButtonLight.setBrightness(brightness);
-            long identity = Binder.clearCallingIdentity();
-            try {
-                mBatteryStats.noteScreenBrightness(brightness);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "RemoteException calling noteScreenBrightness on BatteryStatsService", e);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-            mScreenBrightnessAnimator.animateTo(brightness, SCREEN_BRIGHT_BIT, 0);
-        }
-    }
-
-    public void setAutoBrightnessAdjustment(float adj) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-        synchronized (mLocks) {
-            mLightSensorAdjustSetting = adj;
-            if (mSensorManager != null && mLightSensorEnabled) {
-                // clear calling identity so sensor manager battery stats are accurate
-                long identity = Binder.clearCallingIdentity();
-                try {
-                    // force recompute of backlight values
-                    if (mLightSensorValue >= 0) {
-                        int value = (int)mLightSensorValue;
-                        mLightSensorValue = -1;
-                        handleLightSensorValue(value, true);
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(identity);
-                }
-            }
-        }
-    }
-
+    /**
+     * Used by the phone application to make the attention LED flash when ringing.
+     */
+    @Override // Binder call
     public void setAttentionLight(boolean on, int color) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
-        mAttentionLight.setFlashing(color, LightsService.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            setAttentionLightInternal(on, color);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
     }
 
-    private void enableProximityLockLocked() {
-        if (DEBUG_PROXIMITY_SENSOR) {
-            Slog.d(TAG, "enableProximityLockLocked");
+    private void setAttentionLightInternal(boolean on, int color) {
+        LightsService.Light light;
+        synchronized (mLock) {
+            if (!mSystemReady) {
+                return;
+            }
+            light = mAttentionLight;
         }
-        if (!mProximitySensorEnabled) {
-            // clear calling identity so sensor manager battery stats are accurate
-            long identity = Binder.clearCallingIdentity();
-            try {
-                mSensorManager.registerListener(mProximityListener, mProximitySensor,
-                        SensorManager.SENSOR_DELAY_NORMAL);
-                mProximitySensorEnabled = true;
-            } finally {
-                Binder.restoreCallingIdentity(identity);
+
+        // Control light outside of lock.
+        light.setFlashing(color, LightsService.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
+    }
+
+    /**
+     * Used by the Watchdog.
+     */
+    public long timeSinceScreenWasLastOn() {
+        synchronized (mLock) {
+            if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
+                return 0;
+            }
+            return SystemClock.elapsedRealtime() - mLastScreenOffEventElapsedRealTime;
+        }
+    }
+
+    /**
+     * Used by the window manager to override the screen brightness based on the
+     * current foreground activity.
+     *
+     * This method must only be called by the window manager.
+     *
+     * @param brightness The overridden brightness, or -1 to disable the override.
+     */
+    public void setScreenBrightnessOverrideFromWindowManager(int brightness) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            setScreenBrightnessOverrideFromWindowManagerInternal(brightness);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private void setScreenBrightnessOverrideFromWindowManagerInternal(int brightness) {
+        synchronized (mLock) {
+            if (mScreenBrightnessOverrideFromWindowManager != brightness) {
+                mScreenBrightnessOverrideFromWindowManager = brightness;
+                mDirty |= DIRTY_SETTINGS;
+                updatePowerStateLocked();
             }
         }
     }
 
-    private void disableProximityLockLocked() {
-        if (DEBUG_PROXIMITY_SENSOR) {
-            Slog.d(TAG, "disableProximityLockLocked");
+    /**
+     * Used by the window manager to override the button brightness based on the
+     * current foreground activity.
+     *
+     * This method must only be called by the window manager.
+     *
+     * @param brightness The overridden brightness, or -1 to disable the override.
+     */
+    public void setButtonBrightnessOverrideFromWindowManager(int brightness) {
+        // Do nothing.
+        // Button lights are not currently supported in the new implementation.
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+    }
+
+    /**
+     * Used by the settings application and brightness control widgets to
+     * temporarily override the current screen brightness setting so that the
+     * user can observe the effect of an intended settings change without applying
+     * it immediately.
+     *
+     * The override will be canceled when the setting value is next updated.
+     *
+     * @param brightness The overridden brightness.
+     *
+     * @see Settings.System#SCREEN_BRIGHTNESS
+     */
+    @Override // Binder call
+    public void setTemporaryScreenBrightnessSettingOverride(int brightness) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            setTemporaryScreenBrightnessSettingOverrideInternal(brightness);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
-        if (mProximitySensorEnabled) {
-            // clear calling identity so sensor manager battery stats are accurate
-            long identity = Binder.clearCallingIdentity();
-            try {
-                mSensorManager.unregisterListener(mProximityListener);
-                mHandler.removeCallbacks(mProximityTask);
-                if (mProximityPartialLock.isHeld()) {
-                    mProximityPartialLock.release();
-                }
-                mProximitySensorEnabled = false;
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-            if (mProximitySensorActive) {
-                mProximitySensorActive = false;
-                if (DEBUG_PROXIMITY_SENSOR) {
-                    Slog.d(TAG, "disableProximityLockLocked mProxIgnoredBecauseScreenTurnedOff="
-                            + mProxIgnoredBecauseScreenTurnedOff);
-                }
-                if (!mProxIgnoredBecauseScreenTurnedOff) {
-                    forceUserActivityLocked();
-                }
+    }
+
+    private void setTemporaryScreenBrightnessSettingOverrideInternal(int brightness) {
+        synchronized (mLock) {
+            if (mTemporaryScreenBrightnessSettingOverride != brightness) {
+                mTemporaryScreenBrightnessSettingOverride = brightness;
+                mDirty |= DIRTY_SETTINGS;
+                updatePowerStateLocked();
             }
         }
     }
 
-    private void proximityChangedLocked(boolean active) {
-        if (DEBUG_PROXIMITY_SENSOR) {
-            Slog.d(TAG, "proximityChangedLocked, active: " + active);
+    /**
+     * Used by the settings application and brightness control widgets to
+     * temporarily override the current screen auto-brightness adjustment setting so that the
+     * user can observe the effect of an intended settings change without applying
+     * it immediately.
+     *
+     * The override will be canceled when the setting value is next updated.
+     *
+     * @param adj The overridden brightness, or Float.NaN to disable the override.
+     *
+     * @see Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ
+     */
+    @Override // Binder call
+    public void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float adj) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(adj);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
-        if (!mProximitySensorEnabled) {
-            Slog.d(TAG, "Ignoring proximity change after sensor is disabled");
+    }
+
+    private void setTemporaryScreenAutoBrightnessAdjustmentSettingOverrideInternal(float adj) {
+        synchronized (mLock) {
+            // Note: This condition handles NaN because NaN is not equal to any other
+            // value, including itself.
+            if (mTemporaryScreenAutoBrightnessAdjustmentSettingOverride != adj) {
+                mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = adj;
+                mDirty |= DIRTY_SETTINGS;
+                updatePowerStateLocked();
+            }
+        }
+    }
+
+    /**
+     * Low-level function turn the device off immediately, without trying
+     * to be clean.  Most people should use {@link ShutdownThread} for a clean shutdown.
+     */
+    public static void lowLevelShutdown() {
+        nativeShutdown();
+    }
+
+    /**
+     * Low-level function to reboot the device.
+     *
+     * @param reason code to pass to the kernel (e.g. "recovery"), or null.
+     * @throws IOException if reboot fails for some reason (eg, lack of
+     *         permission)
+     */
+    public static void lowLevelReboot(String reason) throws IOException {
+        nativeReboot(reason);
+    }
+
+    @Override // Watchdog.Monitor implementation
+    public void monitor() {
+        // Grab and release lock for watchdog monitor to detect deadlocks.
+        synchronized (mLock) {
+        }
+    }
+
+    @Override // Binder call
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump PowerManager from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid());
             return;
         }
-        if (active) {
-            if (DEBUG_PROXIMITY_SENSOR) {
-                Slog.d(TAG, "b mProxIgnoredBecauseScreenTurnedOff="
-                        + mProxIgnoredBecauseScreenTurnedOff);
-            }
-            if (!mProxIgnoredBecauseScreenTurnedOff) {
-                goToSleepLocked(SystemClock.uptimeMillis(),
-                        WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR);
-            }
-            mProximitySensorActive = true;
-        } else {
-            // proximity sensor negative events trigger as user activity.
-            // temporarily set mUserActivityAllowed to true so this will work
-            // even when the keyguard is on.
-            mProximitySensorActive = false;
-            if (DEBUG_PROXIMITY_SENSOR) {
-                Slog.d(TAG, "b mProxIgnoredBecauseScreenTurnedOff="
-                        + mProxIgnoredBecauseScreenTurnedOff);
-            }
-            if (!mProxIgnoredBecauseScreenTurnedOff) {
-                forceUserActivityLocked();
+
+        pw.println("POWER MANAGER (dumpsys power)\n");
+
+        final DisplayPowerController dpc;
+        synchronized (mLock) {
+            pw.println("Power Manager State:");
+            pw.println("  mDirty=0x" + Integer.toHexString(mDirty));
+            pw.println("  mWakefulness=" + wakefulnessToString(mWakefulness));
+            pw.println("  mIsPowered=" + mIsPowered);
+            pw.println("  mStayOn=" + mStayOn);
+            pw.println("  mBootCompleted=" + mBootCompleted);
+            pw.println("  mSystemReady=" + mSystemReady);
+            pw.println("  mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
+            pw.println("  mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary));
+            pw.println("  mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
+            pw.println("  mSandmanScheduled=" + mSandmanScheduled);
+            pw.println("  mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
+            pw.println("  mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
+            pw.println("  mSendWakeUpFinishedNotificationWhenReady="
+                    + mSendWakeUpFinishedNotificationWhenReady);
+            pw.println("  mSendGoToSleepFinishedNotificationWhenReady="
+                    + mSendGoToSleepFinishedNotificationWhenReady);
+            pw.println("  mLastUserActivityTime=" + TimeUtils.formatUptime(mLastUserActivityTime));
+            pw.println("  mLastUserActivityTimeNoChangeLights="
+                    + TimeUtils.formatUptime(mLastUserActivityTimeNoChangeLights));
+            pw.println("  mDisplayReady=" + mDisplayReady);
+            pw.println("  mHoldingWakeLockSuspendBlocker=" + mHoldingWakeLockSuspendBlocker);
+
+            pw.println();
+            pw.println("Settings and Configuration:");
+            pw.println("  mDreamsSupportedConfig=" + mDreamsSupportedConfig);
+            pw.println("  mDreamsEnabledSetting=" + mDreamsEnabledSetting);
+            pw.println("  mScreenOffTimeoutSetting=" + mScreenOffTimeoutSetting);
+            pw.println("  mMaximumScreenOffTimeoutFromDeviceAdmin="
+                    + mMaximumScreenOffTimeoutFromDeviceAdmin + " (enforced="
+                    + isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked() + ")");
+            pw.println("  mStayOnWhilePluggedInSetting=" + mStayOnWhilePluggedInSetting);
+            pw.println("  mScreenBrightnessSetting=" + mScreenBrightnessSetting);
+            pw.println("  mScreenAutoBrightnessAdjustmentSetting="
+                    + mScreenAutoBrightnessAdjustmentSetting);
+            pw.println("  mScreenBrightnessModeSetting=" + mScreenBrightnessModeSetting);
+            pw.println("  mScreenBrightnessOverrideFromWindowManager="
+                    + mScreenBrightnessOverrideFromWindowManager);
+            pw.println("  mTemporaryScreenBrightnessSettingOverride="
+                    + mTemporaryScreenBrightnessSettingOverride);
+            pw.println("  mTemporaryScreenAutoBrightnessAdjustmentSettingOverride="
+                    + mTemporaryScreenAutoBrightnessAdjustmentSettingOverride);
+            pw.println("  mScreenBrightnessSettingMinimum=" + mScreenBrightnessSettingMinimum);
+            pw.println("  mScreenBrightnessSettingMaximum=" + mScreenBrightnessSettingMaximum);
+            pw.println("  mScreenBrightnessSettingDefault=" + mScreenBrightnessSettingDefault);
+
+            pw.println();
+            pw.println("Wake Locks: size=" + mWakeLocks.size());
+            for (WakeLock wl : mWakeLocks) {
+                pw.println("  " + wl);
             }
 
-            if (mProximityWakeLockCount == 0) {
-                // disable sensor if we have no listeners left after proximity negative
-                disableProximityLockLocked();
+            pw.println();
+            pw.println("Suspend Blockers: size=" + mSuspendBlockers.size());
+            for (SuspendBlocker sb : mSuspendBlockers) {
+                pw.println("  " + sb);
+            }
+
+            dpc = mDisplayPowerController;
+        }
+
+        if (dpc != null) {
+            dpc.dump(pw);
+        }
+    }
+
+    private SuspendBlocker createSuspendBlockerLocked(String name) {
+        SuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);
+        mSuspendBlockers.add(suspendBlocker);
+        return suspendBlocker;
+    }
+
+    private static String wakefulnessToString(int wakefulness) {
+        switch (wakefulness) {
+            case WAKEFULNESS_ASLEEP:
+                return "Asleep";
+            case WAKEFULNESS_AWAKE:
+                return "Awake";
+            case WAKEFULNESS_DREAMING:
+                return "Dreaming";
+            case WAKEFULNESS_NAPPING:
+                return "Napping";
+            default:
+                return Integer.toString(wakefulness);
+        }
+    }
+
+    private static WorkSource copyWorkSource(WorkSource workSource) {
+        return workSource != null ? new WorkSource(workSource) : null;
+    }
+
+    private final class BatteryReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            synchronized (mLock) {
+                handleBatteryStateChangedLocked();
             }
         }
     }
 
-    private void enableLightSensorLocked(boolean enable) {
-        if (DEBUG_LIGHT_SENSOR) {
-            Slog.d(TAG, "enableLightSensorLocked enable=" + enable
-                    + " mLightSensorEnabled=" + mLightSensorEnabled
-                    + " mAutoBrightessEnabled=" + mAutoBrightessEnabled
-                    + " mWaitingForFirstLightSensor=" + mWaitingForFirstLightSensor);
+    private final class BootCompletedReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            synchronized (mLock) {
+                handleBootCompletedLocked();
+            }
         }
-        if (!mAutoBrightessEnabled) {
-            enable = false;
+    }
+
+    private final class DockReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            synchronized (mLock) {
+                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
+                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
+                handleDockStateChangedLocked(dockState);
+            }
         }
-        if (mSensorManager != null && mLightSensorEnabled != enable) {
-            mLightSensorEnabled = enable;
-            // clear calling identity so sensor manager battery stats are accurate
-            long identity = Binder.clearCallingIdentity();
+    }
+
+    private final class SettingsObserver extends ContentObserver {
+        public SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            synchronized (mLock) {
+                handleSettingsChangedLocked();
+            }
+        }
+    }
+
+    private final WindowManagerPolicy.ScreenOnListener mScreenOnListener =
+            new WindowManagerPolicy.ScreenOnListener() {
+        @Override
+        public void onScreenOn() {
+        }
+    };
+
+    /**
+     * Handler for asynchronous operations performed by the power manager.
+     */
+    private final class PowerManagerHandler extends Handler {
+        public PowerManagerHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_USER_ACTIVITY_TIMEOUT:
+                    handleUserActivityTimeout();
+                    break;
+                case MSG_SANDMAN:
+                    handleSandman();
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Represents a wake lock that has been acquired by an application.
+     */
+    private final class WakeLock implements IBinder.DeathRecipient {
+        public final IBinder mLock;
+        public int mFlags;
+        public String mTag;
+        public WorkSource mWorkSource;
+        public int mOwnerUid;
+        public int mOwnerPid;
+
+        public WakeLock(IBinder lock, int flags, String tag, WorkSource workSource,
+                int ownerUid, int ownerPid) {
+            mLock = lock;
+            mFlags = flags;
+            mTag = tag;
+            mWorkSource = copyWorkSource(workSource);
+            mOwnerUid = ownerUid;
+            mOwnerPid = ownerPid;
+        }
+
+        @Override
+        public void binderDied() {
+            PowerManagerService.this.handleWakeLockDeath(this);
+        }
+
+        public boolean hasSameProperties(int flags, String tag, WorkSource workSource,
+                int ownerUid, int ownerPid) {
+            return mFlags == flags
+                    && mTag.equals(tag)
+                    && hasSameWorkSource(workSource)
+                    && mOwnerUid == ownerUid
+                    && mOwnerPid == ownerPid;
+        }
+
+        public void updateProperties(int flags, String tag, WorkSource workSource,
+                int ownerUid, int ownerPid) {
+            mFlags = flags;
+            mTag = tag;
+            updateWorkSource(workSource);
+            mOwnerUid = ownerUid;
+            mOwnerPid = ownerPid;
+        }
+
+        public boolean hasSameWorkSource(WorkSource workSource) {
+            return Objects.equal(mWorkSource, workSource);
+        }
+
+        public void updateWorkSource(WorkSource workSource) {
+            mWorkSource = copyWorkSource(workSource);
+        }
+
+        @Override
+        public String toString() {
+            return getLockLevelString()
+                    + " '" + mTag + "'" + getLockFlagsString()
+                    + " (uid=" + mOwnerUid + ", pid=" + mOwnerPid + ", ws=" + mWorkSource + ")";
+        }
+
+        private String getLockLevelString() {
+            switch (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
+                case PowerManager.FULL_WAKE_LOCK:
+                    return "FULL_WAKE_LOCK                ";
+                case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
+                    return "SCREEN_BRIGHT_WAKE_LOCK       ";
+                case PowerManager.SCREEN_DIM_WAKE_LOCK:
+                    return "SCREEN_DIM_WAKE_LOCK          ";
+                case PowerManager.PARTIAL_WAKE_LOCK:
+                    return "PARTIAL_WAKE_LOCK             ";
+                case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
+                    return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
+                default:
+                    return "???                           ";
+            }
+        }
+
+        private String getLockFlagsString() {
+            String result = "";
+            if ((mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
+                result += " ACQUIRE_CAUSES_WAKEUP";
+            }
+            if ((mFlags & PowerManager.ON_AFTER_RELEASE) != 0) {
+                result += " ON_AFTER_RELEASE";
+            }
+            return result;
+        }
+    }
+
+    private final class SuspendBlockerImpl implements SuspendBlocker {
+        private final String mName;
+        private int mReferenceCount;
+
+        public SuspendBlockerImpl(String name) {
+            mName = name;
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
             try {
-                if (enable) {
-                    // reset our highest value when reenabling
-                    mHighestLightSensorValue = -1;
-                    // force recompute of backlight values
-                    final int value = (int)mLightSensorValue;
-                    if (value >= 0) {
-                        mLightSensorValue = -1;
-                        handleLightSensorValue(value, true);
-                    }
-                    mSensorManager.registerListener(mLightListener, mLightSensor,
-                            LIGHT_SENSOR_RATE);
-                } else {
-                    mSensorManager.unregisterListener(mLightListener);
-                    mHandler.removeCallbacks(mAutoBrightnessTask);
-                    mLightSensorPendingDecrease = false;
-                    mLightSensorPendingIncrease = false;
+                if (mReferenceCount != 0) {
+                    Log.wtf(TAG, "Suspend blocker \"" + mName
+                            + "\" was finalized without being released!");
+                    mReferenceCount = 0;
+                    nativeReleaseSuspendBlocker(mName);
                 }
             } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    SensorEventListener mProximityListener = new SensorEventListener() {
-        public void onSensorChanged(SensorEvent event) {
-            long milliseconds = SystemClock.elapsedRealtime();
-            synchronized (mLocks) {
-                float distance = event.values[0];
-                long timeSinceLastEvent = milliseconds - mLastProximityEventTime;
-                mLastProximityEventTime = milliseconds;
-                mHandler.removeCallbacks(mProximityTask);
-                boolean proximityTaskQueued = false;
-
-                // compare against getMaximumRange to support sensors that only return 0 or 1
-                boolean active = (distance >= 0.0 && distance < PROXIMITY_THRESHOLD &&
-                        distance < mProximitySensor.getMaximumRange());
-
-                if (DEBUG_PROXIMITY_SENSOR) {
-                    Slog.d(TAG, "mProximityListener.onSensorChanged active: " + active);
-                }
-                if (timeSinceLastEvent < PROXIMITY_SENSOR_DELAY) {
-                    // enforce delaying atleast PROXIMITY_SENSOR_DELAY before processing
-                    mProximityPendingValue = (active ? 1 : 0);
-                    mHandler.postDelayed(mProximityTask, PROXIMITY_SENSOR_DELAY - timeSinceLastEvent);
-                    proximityTaskQueued = true;
-                } else {
-                    // process the value immediately
-                    mProximityPendingValue = -1;
-                    proximityChangedLocked(active);
-                }
-
-                // update mProximityPartialLock state
-                boolean held = mProximityPartialLock.isHeld();
-                if (!held && proximityTaskQueued) {
-                    // hold wakelock until mProximityTask runs
-                    mProximityPartialLock.acquire();
-                } else if (held && !proximityTaskQueued) {
-                    mProximityPartialLock.release();
-                }
+                super.finalize();
             }
         }
 
-        public void onAccuracyChanged(Sensor sensor, int accuracy) {
-            // ignore
-        }
-    };
-
-    private void handleLightSensorValue(int value, boolean immediate) {
-        long milliseconds = SystemClock.elapsedRealtime();
-        if (mLightSensorValue == -1
-                || milliseconds < mLastScreenOnTime + mLightSensorWarmupTime
-                || mWaitingForFirstLightSensor) {
-            // process the value immediately if screen has just turned on
-            mHandler.removeCallbacks(mAutoBrightnessTask);
-            mLightSensorPendingDecrease = false;
-            mLightSensorPendingIncrease = false;
-            lightSensorChangedLocked(value, immediate);
-        } else {
-            if ((value > mLightSensorValue && mLightSensorPendingDecrease) ||
-                    (value < mLightSensorValue && mLightSensorPendingIncrease) ||
-                    (value == mLightSensorValue) ||
-                    (!mLightSensorPendingDecrease && !mLightSensorPendingIncrease)) {
-                // delay processing to debounce the sensor
-                mHandler.removeCallbacks(mAutoBrightnessTask);
-                mLightSensorPendingDecrease = (value < mLightSensorValue);
-                mLightSensorPendingIncrease = (value > mLightSensorValue);
-                if (mLightSensorPendingDecrease || mLightSensorPendingIncrease) {
-                    mLightSensorPendingValue = value;
-                    mHandler.postDelayed(mAutoBrightnessTask, LIGHT_SENSOR_DELAY);
-                }
-            } else {
-                mLightSensorPendingValue = value;
-            }
-        }
-    }
-
-    SensorEventListener mLightListener = new SensorEventListener() {
         @Override
-        public void onSensorChanged(SensorEvent event) {
-            if (DEBUG_LIGHT_SENSOR) {
-                Slog.d(TAG, "onSensorChanged: light value: " + event.values[0]);
-            }
-            synchronized (mLocks) {
-                // ignore light sensor while screen is turning off
-                if (isScreenTurningOffLocked()) {
-                    return;
-                }
-                handleLightSensorValue((int)event.values[0], mWaitingForFirstLightSensor);
-                if (mWaitingForFirstLightSensor && !mPreparingForScreenOn) {
-                    if (DEBUG_LIGHT_ANIMATION) {
-                        Slog.d(TAG, "onSensorChanged: Clearing mWaitingForFirstLightSensor.");
-                    }
-                    mWaitingForFirstLightSensor = false;
+        public void acquire() {
+            synchronized (this) {
+                mReferenceCount += 1;
+                if (mReferenceCount == 1) {
+                    nativeAcquireSuspendBlocker(mName);
                 }
             }
         }
 
         @Override
-        public void onAccuracyChanged(Sensor sensor, int accuracy) {
-            // ignore
+        public void release() {
+            synchronized (this) {
+                mReferenceCount -= 1;
+                if (mReferenceCount == 0) {
+                    nativeReleaseSuspendBlocker(mName);
+                } else if (mReferenceCount < 0) {
+                    Log.wtf(TAG, "Suspend blocker \"" + mName
+                            + "\" was released without being acquired!", new Throwable());
+                    mReferenceCount = 0;
+                }
+            }
         }
-    };
+
+        @Override
+        public String toString() {
+            synchronized (this) {
+                return mName + ": ref count=" + mReferenceCount;
+            }
+        }
+    }
 }
diff --git a/services/java/com/android/server/power/RampAnimator.java b/services/java/com/android/server/power/RampAnimator.java
new file mode 100644
index 0000000..6f063c3
--- /dev/null
+++ b/services/java/com/android/server/power/RampAnimator.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import android.animation.ValueAnimator;
+import android.util.IntProperty;
+import android.view.Choreographer;
+
+/**
+ * A custom animator that progressively updates a property value at
+ * a given variable rate until it reaches a particular target value.
+ */
+final class RampAnimator<T> {
+    private final T mObject;
+    private final IntProperty<T> mProperty;
+    private final Choreographer mChoreographer;
+
+    private int mCurrentValue;
+    private int mTargetValue;
+    private int mRate;
+
+    private boolean mAnimating;
+    private float mAnimatedValue; // higher precision copy of mCurrentValue
+    private long mLastFrameTimeNanos;
+
+    private boolean mFirstTime = true;
+
+    public RampAnimator(T object, IntProperty<T> property) {
+        mObject = object;
+        mProperty = property;
+        mChoreographer = Choreographer.getInstance();
+    }
+
+    /**
+     * Starts animating towards the specified value.
+     *
+     * If this is the first time the property is being set, the value jumps
+     * directly to the target.
+     *
+     * @param target The target value.
+     * @param rate The convergence rate, in units per second.
+     * @return True if the target differs from the previous target.
+     */
+    public boolean animateTo(int target, int rate) {
+        // Immediately jump to the target the first time.
+        if (mFirstTime) {
+            mFirstTime = false;
+            mProperty.setValue(mObject, target);
+            mCurrentValue = target;
+            return true;
+        }
+
+        // Adjust the rate based on the closest target.
+        // If a faster rate is specified, then use the new rate so that we converge
+        // more rapidly based on the new request.
+        // If a slower rate is specified, then use the new rate only if the current
+        // value is somewhere in between the new and the old target meaning that
+        // we will be ramping in a different direction to get there.
+        // Otherwise, continue at the previous rate.
+        if (!mAnimating
+                || rate > mRate
+                || (target <= mCurrentValue && mCurrentValue <= mTargetValue)
+                || (mTargetValue <= mCurrentValue && mCurrentValue <= target)) {
+            mRate = rate;
+        }
+
+        final boolean changed = (mTargetValue != target);
+        mTargetValue = target;
+
+        // Start animating.
+        if (!mAnimating && target != mCurrentValue) {
+            mAnimating = true;
+            mAnimatedValue = mCurrentValue;
+            mLastFrameTimeNanos = System.nanoTime();
+            postCallback();
+        }
+
+        return changed;
+    }
+
+    private void postCallback() {
+        mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mCallback, null);
+    }
+
+    private final Runnable mCallback = new Runnable() {
+        @Override // Choreographer callback
+        public void run() {
+            final long frameTimeNanos = mChoreographer.getFrameTimeNanos();
+            final float timeDelta = (frameTimeNanos - mLastFrameTimeNanos)
+                    * 0.000000001f;
+            final float amount = timeDelta * mRate / ValueAnimator.getDurationScale();
+            mLastFrameTimeNanos = frameTimeNanos;
+
+            // Advance the animated value towards the target at the specified rate
+            // and clamp to the target. This gives us the new current value but
+            // we keep the animated value around to allow for fractional increments
+            // towards the target.
+            int oldCurrentValue = mCurrentValue;
+            if (mTargetValue > mCurrentValue) {
+                mAnimatedValue = Math.min(mAnimatedValue + amount, mTargetValue);
+            } else {
+                mAnimatedValue = Math.max(mAnimatedValue - amount, mTargetValue);
+            }
+            mCurrentValue = (int)Math.round(mAnimatedValue);
+
+            if (oldCurrentValue != mCurrentValue) {
+                mProperty.setValue(mObject, mCurrentValue);
+            }
+
+            if (mTargetValue != mCurrentValue) {
+                postCallback();
+            } else {
+                mAnimating = false;
+            }
+        }
+    };
+}
diff --git a/services/java/com/android/server/power/SuspendBlocker.java b/services/java/com/android/server/power/SuspendBlocker.java
new file mode 100644
index 0000000..70b278a
--- /dev/null
+++ b/services/java/com/android/server/power/SuspendBlocker.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+/**
+ * Low-level suspend blocker mechanism equivalent to holding a partial wake lock.
+ *
+ * This interface is used internally to avoid introducing internal dependencies
+ * on the high-level wake lock mechanism.
+ */
+interface SuspendBlocker {
+    /**
+     * Acquires the suspend blocker.
+     * Prevents the CPU from going to sleep.
+     *
+     * Calls to acquire() nest and must be matched by the same number
+     * of calls to release().
+     */
+    void acquire();
+
+    /**
+     * Releases the suspend blocker.
+     * Allows the CPU to go to sleep if no other suspend blockers are held.
+     *
+     * It is an error to call release() if the suspend blocker has not been acquired.
+     * The system may crash.
+     */
+    void release();
+}
diff --git a/services/java/com/android/server/usb/UsbDebuggingManager.java b/services/java/com/android/server/usb/UsbDebuggingManager.java
new file mode 100644
index 0000000..a3b45c7
--- /dev/null
+++ b/services/java/com/android/server/usb/UsbDebuggingManager.java
@@ -0,0 +1,322 @@
+/*
+ * 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 an
+ * limitations under the License.
+ */
+
+package com.android.server.usb;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.Base64;
+
+import java.lang.Thread;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.security.MessageDigest;
+import java.util.Arrays;
+
+public class UsbDebuggingManager implements Runnable {
+    private static final String TAG = "UsbDebuggingManager";
+    private static final boolean DEBUG = false;
+
+    private final String ADBD_SOCKET = "adbd";
+    private final String ADB_DIRECTORY = "misc/adb";
+    private final String ADB_KEYS_FILE = "adb_keys";
+    private final int BUFFER_SIZE = 4096;
+
+    private final Context mContext;
+    private final Thread mThread;
+    private final Handler mHandler;
+    private final HandlerThread mHandlerThread;
+    private boolean mAdbEnabled = false;
+    private String mFingerprints;
+    private LocalSocket mSocket = null;
+    private OutputStream mOutputStream = null;
+
+    public UsbDebuggingManager(Context context) {
+        mThread = new Thread(this);
+        mHandlerThread = new HandlerThread("UsbDebuggingHandler");
+        mHandlerThread.start();
+        mHandler = new UsbDebuggingHandler(mHandlerThread.getLooper());
+        mContext = context;
+    }
+
+    private void listenToSocket() throws IOException {
+        try {
+            byte[] buffer = new byte[BUFFER_SIZE];
+            LocalSocketAddress address = new LocalSocketAddress(ADBD_SOCKET,
+                                         LocalSocketAddress.Namespace.RESERVED);
+            InputStream inputStream = null;
+
+            mSocket = new LocalSocket();
+            mSocket.connect(address);
+
+            mOutputStream = mSocket.getOutputStream();
+            inputStream = mSocket.getInputStream();
+
+            while (true) {
+                int count = inputStream.read(buffer);
+                if (count < 0) {
+                    Slog.e(TAG, "got " + count + " reading");
+                    break;
+                }
+
+                if (buffer[0] == 'P' && buffer[1] == 'K') {
+                    String key = new String(Arrays.copyOfRange(buffer, 2, count));
+                    Slog.d(TAG, "Received public key: " + key);
+                    Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_CONFIRM);
+                    msg.obj = key;
+                    mHandler.sendMessage(msg);
+                }
+                else {
+                    Slog.e(TAG, "Wrong message: " + (new String(Arrays.copyOfRange(buffer, 0, 2))));
+                    break;
+                }
+            }
+        } catch (IOException ex) {
+            Slog.e(TAG, "Communication error: ", ex);
+            throw ex;
+        } finally {
+            closeSocket();
+        }
+    }
+
+    @Override
+    public void run() {
+        while (mAdbEnabled) {
+            try {
+                listenToSocket();
+            } catch (Exception e) {
+                /* Don't loop too fast if adbd dies, before init restarts it */
+                SystemClock.sleep(1000);
+            }
+        }
+    }
+
+    private void closeSocket() {
+        try {
+            mOutputStream.close();
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed closing output stream: " + e);
+        }
+
+        try {
+            mSocket.close();
+        } catch (IOException ex) {
+            Slog.e(TAG, "Failed closing socket: " + ex);
+        }
+    }
+
+    private void sendResponse(String msg) {
+        if (mOutputStream != null) {
+            try {
+                mOutputStream.write(msg.getBytes());
+            }
+            catch (IOException ex) {
+                Slog.e(TAG, "Failed to write response:", ex);
+            }
+        }
+    }
+
+    class UsbDebuggingHandler extends Handler {
+        private static final int MESSAGE_ADB_ENABLED = 1;
+        private static final int MESSAGE_ADB_DISABLED = 2;
+        private static final int MESSAGE_ADB_ALLOW = 3;
+        private static final int MESSAGE_ADB_DENY = 4;
+        private static final int MESSAGE_ADB_CONFIRM = 5;
+
+        public UsbDebuggingHandler(Looper looper) {
+            super(looper);
+        }
+
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MESSAGE_ADB_ENABLED:
+                    if (mAdbEnabled)
+                        break;
+
+                    mAdbEnabled = true;
+
+                    mThread.start();
+
+                    break;
+
+                case MESSAGE_ADB_DISABLED:
+                    if (!mAdbEnabled)
+                        break;
+
+                    mAdbEnabled = false;
+                    closeSocket();
+
+                    try {
+                        mThread.join();
+                    } catch (Exception ex) {
+                    }
+
+                    mOutputStream = null;
+                    mSocket = null;
+
+                case MESSAGE_ADB_ALLOW: {
+                    String key = (String)msg.obj;
+                    String fingerprints = getFingerprints(key);
+
+                    if (!fingerprints.equals(mFingerprints)) {
+                        Slog.e(TAG, "Fingerprints do not match. Got "
+                                + fingerprints + ", expected " + mFingerprints);
+                        break;
+                    }
+
+                    if (msg.arg1 == 1) {
+                        writeKey(key);
+                    }
+
+                    sendResponse("OK");
+                    break;
+                }
+
+                case MESSAGE_ADB_DENY:
+                    sendResponse("NO");
+                    break;
+
+                case MESSAGE_ADB_CONFIRM: {
+                    String key = (String)msg.obj;
+                    mFingerprints = getFingerprints(key);
+                    showConfirmationDialog(key, mFingerprints);
+                    break;
+                }
+            }
+        }
+    }
+
+    private String getFingerprints(String key) {
+        String hex = "0123456789ABCDEF";
+        StringBuilder sb = new StringBuilder();
+        MessageDigest digester;
+
+        try {
+            digester = MessageDigest.getInstance("MD5");
+        } catch (Exception ex) {
+            Slog.e(TAG, "Error getting digester: " + ex);
+            return "";
+        }
+
+        byte[] base64_data = key.split("\\s+")[0].getBytes();
+        byte[] digest = digester.digest(Base64.decode(base64_data, Base64.DEFAULT));
+
+        for (int i = 0; i < digest.length; i++) {
+            sb.append(hex.charAt((digest[i] >> 4) & 0xf));
+            sb.append(hex.charAt(digest[i] & 0xf));
+            if (i < digest.length - 1)
+                sb.append(":");
+        }
+        return sb.toString();
+    }
+
+    private void showConfirmationDialog(String key, String fingerprints) {
+        Intent dialogIntent = new Intent();
+
+        dialogIntent.setClassName("com.android.systemui",
+                "com.android.systemui.usb.UsbDebuggingActivity");
+        dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        dialogIntent.putExtra("key", key);
+        dialogIntent.putExtra("fingerprints", fingerprints);
+        try {
+            mContext.startActivity(dialogIntent);
+        } catch (ActivityNotFoundException e) {
+            Slog.e(TAG, "unable to start UsbDebuggingActivity");
+        }
+    }
+
+    private void writeKey(String key) {
+        File dataDir = Environment.getDataDirectory();
+        File adbDir = new File(dataDir, ADB_DIRECTORY);
+
+        if (!adbDir.exists()) {
+            Slog.e(TAG, "ADB data directory does not exist");
+            return;
+        }
+
+        try {
+            File keyFile = new File(adbDir, ADB_KEYS_FILE);
+
+            if (!keyFile.exists()) {
+                keyFile.createNewFile();
+                FileUtils.setPermissions(keyFile.toString(),
+                    FileUtils.S_IRUSR | FileUtils.S_IWUSR |
+                    FileUtils.S_IRGRP, -1, -1);
+            }
+
+            FileOutputStream fo = new FileOutputStream(keyFile, true);
+            fo.write(key.getBytes());
+            fo.write('\n');
+            fo.close();
+        }
+        catch (IOException ex) {
+            Slog.e(TAG, "Error writing key:" + ex);
+        }
+    }
+
+
+    public void setAdbEnabled(boolean enabled) {
+        mHandler.sendEmptyMessage(enabled ? UsbDebuggingHandler.MESSAGE_ADB_ENABLED
+                                          : UsbDebuggingHandler.MESSAGE_ADB_DISABLED);
+    }
+
+    public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
+        Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_ALLOW);
+        msg.arg1 = alwaysAllow ? 1 : 0;
+        msg.obj = publicKey;
+        mHandler.sendMessage(msg);
+    }
+
+    public void denyUsbDebugging() {
+        mHandler.sendEmptyMessage(UsbDebuggingHandler.MESSAGE_ADB_DENY);
+    }
+
+
+    public void dump(FileDescriptor fd, PrintWriter pw) {
+        pw.println("  USB Debugging State:");
+        pw.println("    Connected to adbd: " + (mOutputStream != null));
+        pw.println("    Last key received: " + mFingerprints);
+        pw.println("    User keys:");
+        try {
+            pw.println(FileUtils.readTextFile(new File("/data/misc/adb/adb_keys"), 0, null));
+        } catch (IOException e) {
+            pw.println("IOException: " + e);
+        }
+        pw.println("    System keys:");
+        try {
+            pw.println(FileUtils.readTextFile(new File("/adb_keys"), 0, null));
+        } catch (IOException e) {
+            pw.println("IOException: " + e);
+        }
+    }
+}
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index a115345c..ddecf14 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -114,6 +114,7 @@
     private boolean mAudioSourceEnabled;
     private Map<String, List<Pair<String, String>>> mOemModeMap;
     private String[] mAccessoryStrings;
+    private UsbDebuggingManager mDebuggingManager;
 
     private class AdbSettingsObserver extends ContentObserver {
         public AdbSettingsObserver() {
@@ -166,6 +167,10 @@
             if (DEBUG) Slog.d(TAG, "accessory attached at boot");
             startAccessoryMode();
         }
+
+        if ("1".equals(SystemProperties.get("ro.adb.secure"))) {
+            mDebuggingManager = new UsbDebuggingManager(context);
+        }
     }
 
     public void systemReady() {
@@ -425,6 +430,9 @@
                 setEnabledFunctions(mDefaultFunctions, true);
                 updateAdbNotification();
             }
+            if (mDebuggingManager != null) {
+                mDebuggingManager.setAdbEnabled(mAdbEnabled);
+            }
         }
 
         private void setEnabledFunctions(String functions, boolean makeDefault) {
@@ -601,6 +609,9 @@
                     if (mCurrentAccessory != null) {
                         mSettingsManager.accessoryAttached(mCurrentAccessory);
                     }
+                    if (mDebuggingManager != null) {
+                        mDebuggingManager.setAdbEnabled(mAdbEnabled);
+                    }
                     break;
             }
         }
@@ -802,10 +813,25 @@
         return usbFunctions;
     }
 
+    public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
+        if (mDebuggingManager != null) {
+            mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);
+        }
+    }
+
+    public void denyUsbDebugging() {
+        if (mDebuggingManager != null) {
+            mDebuggingManager.denyUsbDebugging();
+        }
+    }
+
     public void dump(FileDescriptor fd, PrintWriter pw) {
         if (mHandler != null) {
             mHandler.dump(fd, pw);
         }
+        if (mDebuggingManager != null) {
+            mDebuggingManager.dump(fd, pw);
+        }
     }
 
     private native String[] nativeGetAccessoryStrings();
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index 0205ef8..bebcd56 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -164,6 +164,16 @@
         }
     }
 
+    public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+        mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey);
+    }
+
+    public void denyUsbDebugging() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+        mDeviceManager.denyUsbDebugging();
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
diff --git a/services/java/com/android/server/usb/UsbSettingsManager.java b/services/java/com/android/server/usb/UsbSettingsManager.java
index 7dde340..9b3459b 100644
--- a/services/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/java/com/android/server/usb/UsbSettingsManager.java
@@ -545,6 +545,10 @@
             defaultPackage = mDevicePreferenceMap.get(new DeviceFilter(device));
         }
 
+        // Send broadcast to running activity with registered intent
+        mContext.sendBroadcast(intent);
+
+        // Start activity with registered intent
         resolveActivity(intent, matches, defaultPackage, device, null);
     }
 
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java
index 691e2aa..c25f010 100644
--- a/services/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/java/com/android/server/wm/AppWindowAnimator.java
@@ -47,7 +47,7 @@
     final Transformation thumbnailTransformation = new Transformation();
 
     /** WindowStateAnimator from mAppAnimator.allAppWindows as of last performLayout */
-    ArrayList<WindowStateAnimator> mAllAppWinAnimators;
+    ArrayList<WindowStateAnimator> mAllAppWinAnimators = new ArrayList<WindowStateAnimator>();
 
     static final Animation sDummyAnimation = new DummyAnimation();
 
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 142c60d..7d85d89 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -42,6 +42,7 @@
     static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200;
 
     final Context mContext;
+    final Display mDisplay;
     Surface mSurface;
     BlackFrame mCustomBlackFrame;
     BlackFrame mExitingBlackFrame;
@@ -186,9 +187,10 @@
                 pw.println();
     }
 
-    public ScreenRotationAnimation(Context context, SurfaceSession session,
+    public ScreenRotationAnimation(Context context, Display display, SurfaceSession session,
             boolean inTransaction, int originalWidth, int originalHeight, int originalRotation) {
         mContext = context;
+        mDisplay = display;
 
         // Screenshot does NOT include rotation!
         if (originalRotation == Surface.ROTATION_90
@@ -213,13 +215,13 @@
         try {
             try {
                 if (WindowManagerService.DEBUG_SURFACE_TRACE) {
-                    mSurface = new SurfaceTrace(session, 0, "FreezeSurface", Display.DEFAULT_DISPLAY,
-                        mWidth, mHeight,
-                        PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
+                    mSurface = new SurfaceTrace(session, 0, "FreezeSurface",
+                            mDisplay.getLayerStack(), mWidth, mHeight,
+                            PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
                 } else {
-                    mSurface = new Surface(session, 0, "FreezeSurface", Display.DEFAULT_DISPLAY,
-                        mWidth, mHeight,
-                        PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
+                    mSurface = new Surface(session, 0, "FreezeSurface",
+                            mDisplay.getLayerStack(), mWidth, mHeight,
+                            PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
                 }
                 if (!mSurface.isValid()) {
                     // Screenshot failed, punt.
diff --git a/services/java/com/android/server/wm/StrictModeFlash.java b/services/java/com/android/server/wm/StrictModeFlash.java
index 4b072c3..775aa0f 100644
--- a/services/java/com/android/server/wm/StrictModeFlash.java
+++ b/services/java/com/android/server/wm/StrictModeFlash.java
@@ -22,8 +22,6 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.Region;
-import android.util.DisplayMetrics;
-import android.util.Slog;
 import android.view.Display;
 import android.view.Surface;
 import android.view.SurfaceSession;
@@ -39,7 +37,7 @@
 
     public StrictModeFlash(Display display, SurfaceSession session) {
         try {
-            mSurface = new Surface(session, 0, "StrictModeFlash", Display.DEFAULT_DISPLAY,
+            mSurface = new Surface(session, 0, "StrictModeFlash", display.getLayerStack(),
                 1, 1, PixelFormat.TRANSLUCENT, 0);
         } catch (Surface.OutOfResourcesException e) {
             return;
diff --git a/services/java/com/android/server/wm/Watermark.java b/services/java/com/android/server/wm/Watermark.java
index 12076d8..5901cc8 100644
--- a/services/java/com/android/server/wm/Watermark.java
+++ b/services/java/com/android/server/wm/Watermark.java
@@ -35,6 +35,7 @@
  * Displays a watermark on top of the window manager's windows.
  */
 class Watermark {
+    final Display mDisplay;
     final String[] mTokens;
     final String mText;
     final Paint mTextPaint;
@@ -50,7 +51,7 @@
     int mLastDH;
     boolean mDrawNeeded;
 
-    Watermark(DisplayMetrics dm, SurfaceSession session, String[] tokens) {
+    Watermark(Display display, DisplayMetrics dm, SurfaceSession session, String[] tokens) {
         if (false) {
             Log.i(WindowManagerService.TAG, "*********************** WATERMARK");
             for (int i=0; i<tokens.length; i++) {
@@ -58,6 +59,7 @@
             }
         }
 
+        mDisplay = display;
         mTokens = tokens;
 
         StringBuilder builder = new StringBuilder(32);
@@ -112,7 +114,7 @@
 
         try {
             mSurface = new Surface(session, 0,
-                    "WatermarkSurface", Display.DEFAULT_DISPLAY,
+                    "WatermarkSurface", mDisplay.getLayerStack(),
                     1, 1, PixelFormat.TRANSLUCENT, 0);
             mSurface.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER*100);
             mSurface.setPosition(0, 0);
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 0dbe692..1defa49 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -190,8 +190,8 @@
             for (int i = 0; i < N; i++) {
                 final AppWindowAnimParams params = layoutToAnim.mAppWindowAnimParams.get(i);
                 AppWindowAnimator appAnimator = params.mAppAnimator;
-                appAnimator.mAllAppWinAnimators =
-                        new ArrayList<WindowStateAnimator>(params.mWinAnimators);
+                appAnimator.mAllAppWinAnimators.clear();
+                appAnimator.mAllAppWinAnimators.addAll(params.mWinAnimators);
                 mAppAnimators.add(appAnimator);
             }
         }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 680ae4c0..b0c5835 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -57,6 +57,7 @@
 import android.app.IActivityManager;
 import android.app.StatusBarManager;
 import android.app.admin.DevicePolicyManager;
+import android.animation.ValueAnimator;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -93,6 +94,7 @@
 import android.os.SystemProperties;
 import android.os.TokenWatcher;
 import android.os.Trace;
+import android.os.WorkSource;
 import android.provider.Settings;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
@@ -126,7 +128,7 @@
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
-import android.view.WindowManagerImpl;
+import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicy;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerPolicy.FakeWindow;
@@ -317,15 +319,25 @@
     final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            mPolicy.enableKeyguard(true);
-            synchronized(mKeyguardTokenWatcher) {
-                // lazily evaluate this next time we're asked to disable keyguard
-                mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN;
-                mKeyguardDisabled = false;
+            final String action = intent.getAction();
+            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) {
+                mPolicy.enableKeyguard(true);
+                synchronized(mKeyguardTokenWatcher) {
+                    // lazily evaluate this next time we're asked to disable keyguard
+                    mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN;
+                    mKeyguardDisabled = false;
+                }
+            } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+                final int newUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
+                Slog.v(TAG, "Switching user from " + mCurrentUserId + " to " + newUserId);
+                mCurrentUserId = newUserId;
             }
         }
     };
 
+    // Current user when multi-user is enabled. Don't show windows of non-current user.
+    int mCurrentUserId;
+
     final Context mContext;
 
     final boolean mHaveInputMethods;
@@ -511,7 +523,8 @@
     int mNextAppTransitionType = ActivityOptions.ANIM_NONE;
     String mNextAppTransitionPackage;
     Bitmap mNextAppTransitionThumbnail;
-    boolean mNextAppTransitionDelayed;
+    // Used for thumbnail transitions. True if we're scaling up, false if scaling down
+    boolean mNextAppTransitionScaleUp;
     IRemoteCallback mNextAppTransitionCallback;
     int mNextAppTransitionEnter;
     int mNextAppTransitionExit;
@@ -854,7 +867,7 @@
             android.os.Process.setThreadPriority(
                     android.os.Process.THREAD_PRIORITY_FOREGROUND);
             android.os.Process.setCanSelfBackground(false);
-            mPolicy.init(mContext, mService, mService, mPM);
+            mPolicy.init(mContext, mService, mService);
             mService.mAnimator.mAboveUniverseLayer = mPolicy.getAboveUniverseLayer()
                     * TYPE_LAYER_MULTIPLIER
                     + TYPE_LAYER_OFFSET;
@@ -900,16 +913,18 @@
                 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
         mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
                 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
-        mAnimatorDurationScale = Settings.System.getFloat(context.getContentResolver(),
-                Settings.System.ANIMATOR_DURATION_SCALE, mTransitionAnimationScale);
+        setAnimatorDurationScale(Settings.System.getFloat(context.getContentResolver(),
+                Settings.System.ANIMATOR_DURATION_SCALE, mTransitionAnimationScale));
 
         // Track changes to DevicePolicyManager state so we can enable/disable keyguard.
         IntentFilter filter = new IntentFilter();
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+        // Track user switching.
+        filter.addAction(Intent.ACTION_USER_SWITCHED);
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
         mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
-                | PowerManager.ON_AFTER_RELEASE, "KEEP_SCREEN_ON_FLAG");
+                | PowerManager.ON_AFTER_RELEASE, TAG);
         mHoldingScreenWakeLock.setReferenceCounted(false);
 
         mInputManager = new InputManagerService(context, mInputMonitor);
@@ -2139,7 +2154,7 @@
             WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
             Rect outContentInsets, InputChannel outInputChannel) {
         int res = mPolicy.checkAddPermission(attrs);
-        if (res != WindowManagerImpl.ADD_OKAY) {
+        if (res != WindowManagerGlobal.ADD_OKAY) {
             return res;
         }
 
@@ -2155,7 +2170,7 @@
 
             if (mWindowMap.containsKey(client.asBinder())) {
                 Slog.w(TAG, "Window " + client + " is already added");
-                return WindowManagerImpl.ADD_DUPLICATE_ADD;
+                return WindowManagerGlobal.ADD_DUPLICATE_ADD;
             }
 
             if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) {
@@ -2163,13 +2178,13 @@
                 if (attachedWindow == null) {
                     Slog.w(TAG, "Attempted to add window with token that is not a window: "
                           + attrs.token + ".  Aborting.");
-                    return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
+                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                 }
                 if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW
                         && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) {
                     Slog.w(TAG, "Attempted to add window with token that is a sub-window: "
                             + attrs.token + ".  Aborting.");
-                    return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN;
+                    return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                 }
             }
 
@@ -2180,22 +2195,22 @@
                         && attrs.type <= LAST_APPLICATION_WINDOW) {
                     Slog.w(TAG, "Attempted to add application window with unknown token "
                           + attrs.token + ".  Aborting.");
-                    return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
                 if (attrs.type == TYPE_INPUT_METHOD) {
                     Slog.w(TAG, "Attempted to add input method window with unknown token "
                           + attrs.token + ".  Aborting.");
-                    return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
                 if (attrs.type == TYPE_WALLPAPER) {
                     Slog.w(TAG, "Attempted to add wallpaper window with unknown token "
                           + attrs.token + ".  Aborting.");
-                    return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
                 if (attrs.type == TYPE_DREAM) {
                     Slog.w(TAG, "Attempted to add Dream window with unknown token "
                           + attrs.token + ".  Aborting.");
-                    return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
                 token = new WindowToken(this, attrs.token, -1, false);
                 addToken = true;
@@ -2205,35 +2220,35 @@
                 if (atoken == null) {
                     Slog.w(TAG, "Attempted to add window with non-application token "
                           + token + ".  Aborting.");
-                    return WindowManagerImpl.ADD_NOT_APP_TOKEN;
+                    return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
                 } else if (atoken.removed) {
                     Slog.w(TAG, "Attempted to add window with exiting application token "
                           + token + ".  Aborting.");
-                    return WindowManagerImpl.ADD_APP_EXITING;
+                    return WindowManagerGlobal.ADD_APP_EXITING;
                 }
                 if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
                     // No need for this guy!
                     if (localLOGV) Slog.v(
                             TAG, "**** NO NEED TO START: " + attrs.getTitle());
-                    return WindowManagerImpl.ADD_STARTING_NOT_NEEDED;
+                    return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;
                 }
             } else if (attrs.type == TYPE_INPUT_METHOD) {
                 if (token.windowType != TYPE_INPUT_METHOD) {
                     Slog.w(TAG, "Attempted to add input method window with bad token "
                             + attrs.token + ".  Aborting.");
-                      return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
             } else if (attrs.type == TYPE_WALLPAPER) {
                 if (token.windowType != TYPE_WALLPAPER) {
                     Slog.w(TAG, "Attempted to add wallpaper window with bad token "
                             + attrs.token + ".  Aborting.");
-                      return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
             } else if (attrs.type == TYPE_DREAM) {
                 if (token.windowType != TYPE_DREAM) {
                     Slog.w(TAG, "Attempted to add Dream window with bad token "
                             + attrs.token + ".  Aborting.");
-                      return WindowManagerImpl.ADD_BAD_APP_TOKEN;
+                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
             }
 
@@ -2245,13 +2260,13 @@
                 // continue.
                 Slog.w(TAG, "Adding window client " + client.asBinder()
                         + " that is dead, aborting.");
-                return WindowManagerImpl.ADD_APP_EXITING;
+                return WindowManagerGlobal.ADD_APP_EXITING;
             }
 
             mPolicy.adjustWindowParamsLw(win.mAttrs);
 
             res = mPolicy.prepareAddWindowLw(win, attrs);
-            if (res != WindowManagerImpl.ADD_OKAY) {
+            if (res != WindowManagerGlobal.ADD_OKAY) {
                 return res;
             }
 
@@ -2267,7 +2282,7 @@
 
             // From now on, no exceptions or errors allowed!
 
-            res = WindowManagerImpl.ADD_OKAY;
+            res = WindowManagerGlobal.ADD_OKAY;
 
             origId = Binder.clearCallingIdentity();
 
@@ -2311,10 +2326,10 @@
             mPolicy.getContentInsetHintLw(attrs, outContentInsets);
 
             if (mInTouchMode) {
-                res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE;
+                res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
             }
             if (win.mAppToken == null || !win.mAppToken.clientHidden) {
-                res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE;
+                res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
             }
 
             mInputMonitor.setUpdateInputWindowsNeededLw();
@@ -2746,7 +2761,7 @@
             }
 
             winAnimator.mSurfaceDestroyDeferred =
-                    (flags&WindowManagerImpl.RELAYOUT_DEFER_SURFACE_DESTROY) != 0;
+                    (flags&WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY) != 0;
 
             int attrChanges = 0;
             int flagChanges = 0;
@@ -2965,7 +2980,7 @@
             }
 
             mLayoutNeeded = true;
-            win.mGivenInsetsPending = (flags&WindowManagerImpl.RELAYOUT_INSETS_PENDING) != 0;
+            win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
             if (assignLayers) {
                 assignLayersLocked(win.getWindowList());
             }
@@ -3008,10 +3023,10 @@
 
         Binder.restoreCallingIdentity(origId);
 
-        return (inTouchMode ? WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE : 0)
-                | (toBeDisplayed ? WindowManagerImpl.RELAYOUT_RES_FIRST_TIME : 0)
-                | (surfaceChanged ? WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED : 0)
-                | (animating ? WindowManagerImpl.RELAYOUT_RES_ANIMATING : 0);
+        return (inTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0)
+                | (toBeDisplayed ? WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME : 0)
+                | (surfaceChanged ? WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED : 0)
+                | (animating ? WindowManagerGlobal.RELAYOUT_RES_ANIMATING : 0);
     }
 
     public void performDeferredDestroyWindow(Session session, IWindow client) {
@@ -3223,7 +3238,7 @@
     }
 
     private Animation createThumbnailAnimationLocked(int transit,
-            boolean enter, boolean thumb, boolean delayed) {
+            boolean enter, boolean thumb, boolean scaleUp) {
         Animation a;
         final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
@@ -3233,7 +3248,6 @@
         // it  is the standard duration for that.  Otherwise we use the longer
         // task transition duration.
         int duration;
-        int delayDuration = delayed ? 270 : 0;
         switch (transit) {
             case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
             case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
@@ -3241,7 +3255,7 @@
                         com.android.internal.R.integer.config_shortAnimTime);
                 break;
             default:
-                duration = delayed ? 250 : 300;
+                duration = 250;
                 break;
         }
         // TOOD(multidisplay): For now assume all app animation is on the main screen.
@@ -3249,48 +3263,86 @@
         if (thumb) {
             // Animation for zooming thumbnail from its initial size to
             // filling the screen.
-            float scaleW = displayInfo.appWidth/thumbWidth;
-            float scaleH = displayInfo.appHeight/thumbHeight;
+            if (scaleUp) {
+                float scaleW = displayInfo.appWidth / thumbWidth;
+                float scaleH = displayInfo.appHeight / thumbHeight;
 
-            Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
-                    computePivot(mNextAppTransitionStartX, 1/scaleW),
-                    computePivot(mNextAppTransitionStartY, 1/scaleH));
-            AnimationSet set = new AnimationSet(true);
-            Animation alpha = new AlphaAnimation(1, 0);
-            scale.setDuration(duration);
-            scale.setInterpolator(
-                    new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
-            set.addAnimation(scale);
-            alpha.setDuration(duration);
-            set.addAnimation(alpha);
-            set.setFillBefore(true);
-            if (delayDuration > 0) {
-                set.setStartOffset(delayDuration);
+                Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
+                        computePivot(mNextAppTransitionStartX, 1 / scaleW),
+                        computePivot(mNextAppTransitionStartY, 1 / scaleH));
+                AnimationSet set = new AnimationSet(true);
+                Animation alpha = new AlphaAnimation(1, 0);
+                scale.setDuration(duration);
+                scale.setInterpolator(
+                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
+                set.addAnimation(scale);
+                alpha.setDuration(duration);
+                set.addAnimation(alpha);
+                set.setFillBefore(true);
+                a = set;
+            } else {
+                float scaleW = displayInfo.appWidth / thumbWidth;
+                float scaleH = displayInfo.appHeight / thumbHeight;
+
+                Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
+                        computePivot(mNextAppTransitionStartX, 1 / scaleW),
+                        computePivot(mNextAppTransitionStartY, 1 / scaleH));
+                AnimationSet set = new AnimationSet(true);
+                Animation alpha = new AlphaAnimation(1, 1);
+                scale.setDuration(duration);
+                scale.setInterpolator(
+                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
+                set.addAnimation(scale);
+                alpha.setDuration(duration);
+                set.addAnimation(alpha);
+                set.setFillBefore(true);
+
+                a = set;
             }
-            a = set;
         } else if (enter) {
             // Entering app zooms out from the center of the thumbnail.
-            float scaleW = thumbWidth / displayInfo.appWidth;
-            float scaleH = thumbHeight / displayInfo.appHeight;
-            Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
-                    computePivot(mNextAppTransitionStartX, scaleW),
-                    computePivot(mNextAppTransitionStartY, scaleH));
-            scale.setDuration(duration);
-            scale.setInterpolator(
-                    new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
-            scale.setFillBefore(true);
-            if (delayDuration > 0) {
-                scale.setStartOffset(delayDuration);
-            }
-            a = scale;
-        } else {
-            if (delayed) {
-                a = new AlphaAnimation(1, 0);
-                a.setStartOffset(0);
-                a.setDuration(delayDuration - 120);
-                a.setBackgroundColor(0xFF000000);
+            if (scaleUp) {
+                float scaleW = thumbWidth / displayInfo.appWidth;
+                float scaleH = thumbHeight / displayInfo.appHeight;
+                Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
+                        computePivot(mNextAppTransitionStartX, scaleW),
+                        computePivot(mNextAppTransitionStartY, scaleH));
+                scale.setDuration(duration);
+                scale.setInterpolator(
+                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
+                scale.setFillBefore(true);
+                a = scale;
             } else {
-                a = createExitAnimationLocked(transit, duration);
+                // noop animation
+                a = new AlphaAnimation(1, 1);
+                a.setDuration(duration);
+            }
+        } else {
+            // Exiting app
+            if (scaleUp) {
+                // noop animation
+                a = new AlphaAnimation(1, 1);
+                a.setDuration(duration);
+            } else {
+                float scaleW = thumbWidth / displayInfo.appWidth;
+                float scaleH = thumbHeight / displayInfo.appHeight;
+                Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
+                        computePivot(mNextAppTransitionStartX, scaleW),
+                        computePivot(mNextAppTransitionStartY, scaleH));
+                scale.setDuration(duration);
+                scale.setInterpolator(
+                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
+                scale.setFillBefore(true);
+                AnimationSet set = new AnimationSet(true);
+                Animation alpha = new AlphaAnimation(1, 0);
+                set.addAnimation(scale);
+                alpha.setDuration(duration);
+                alpha.setInterpolator(new DecelerateInterpolator(
+                        THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
+                set.addAnimation(alpha);
+                set.setFillBefore(true);
+                set.setZAdjustment(Animation.ZORDER_TOP);
+                a = set;
             }
         }
         a.setFillAfter(true);
@@ -3325,14 +3377,14 @@
                         "applyAnimation: wtoken=" + wtoken
                         + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
                         + " transit=" + transit + " Callers " + Debug.getCallers(3));
-            } else if (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL ||
-                    mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_DELAYED) {
-                boolean delayed = (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_DELAYED);
-                a = createThumbnailAnimationLocked(transit, enter, false, delayed);
+            } else if (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP ||
+                    mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN) {
+                boolean scaleUp = (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP);
+                a = createThumbnailAnimationLocked(transit, enter, false, scaleUp);
                 initialized = true;
 
                 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
-                    String animName = delayed ? "ANIM_THUMBNAIL_DELAYED" : "ANIM_THUMBNAIL";
+                    String animName = scaleUp ? "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
                     Slog.v(TAG, "applyAnimation: wtoken=" + wtoken
                             + " anim=" + a + " nextAppTransition=" + animName
                             + " transit=" + transit + " Callers " + Debug.getCallers(3));
@@ -4007,14 +4059,14 @@
     }
 
     public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX,
-            int startY, IRemoteCallback startedCallback, boolean delayed) {
+            int startY, IRemoteCallback startedCallback, boolean scaleUp) {
         synchronized(mWindowMap) {
             if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
-                mNextAppTransitionType = delayed
-                        ? ActivityOptions.ANIM_THUMBNAIL_DELAYED : ActivityOptions.ANIM_THUMBNAIL;
+                mNextAppTransitionType = scaleUp
+                        ? ActivityOptions.ANIM_THUMBNAIL_SCALE_UP : ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
                 mNextAppTransitionPackage = null;
                 mNextAppTransitionThumbnail = srcThumb;
-                mNextAppTransitionDelayed = delayed;
+                mNextAppTransitionScaleUp = scaleUp;
                 mNextAppTransitionStartX = startX;
                 mNextAppTransitionStartY = startY;
                 scheduleAnimationCallback(mNextAppTransitionCallback);
@@ -5160,7 +5212,7 @@
                 mTransitionAnimationScale = fixScale(scales[1]);
             }
             if (scales.length >= 3) {
-                mAnimatorDurationScale = fixScale(scales[2]);
+                setAnimatorDurationScale(fixScale(scales[2]));
             }
         }
 
@@ -5168,6 +5220,11 @@
         mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
     }
 
+    private void setAnimatorDurationScale(float scale) {
+        mAnimatorDurationScale = scale;
+        ValueAnimator.setDurationScale(scale);
+    }
+
     public float getAnimationScale(int which) {
         switch (which) {
             case 0: return mWindowAnimationScale;
@@ -5213,14 +5270,14 @@
 
     // Called by window manager policy.  Not exposed externally.
     @Override
-    public void shutdown() {
-        ShutdownThread.shutdown(mContext, true);
+    public void shutdown(boolean confirm) {
+        ShutdownThread.shutdown(mContext, confirm);
     }
 
     // Called by window manager policy.  Not exposed externally.
     @Override
-    public void rebootSafeMode() {
-        ShutdownThread.rebootSafeMode(mContext, true);
+    public void rebootSafeMode(boolean confirm) {
+        ShutdownThread.rebootSafeMode(mContext, confirm);
     }
 
     public void setInputFilter(IInputFilter filter) {
@@ -5868,7 +5925,7 @@
             }
         }
 
-        rebuildBlackFrame();
+        rebuildBlackFrameLocked();
 
         final WindowList windows = displayContent.getWindowList();
         for (int i = windows.size() - 1; i >= 0; i--) {
@@ -6885,6 +6942,8 @@
         displayReady(Display.DEFAULT_DISPLAY);
 
         synchronized(mWindowMap) {
+            readForcedDisplaySizeAndDensityLocked(getDefaultDisplayContent());
+
             WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
             mDisplay = wm.getDefaultDisplay();
             mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
@@ -6906,6 +6965,11 @@
             mPolicy.setInitialDisplaySize(mDisplay, displayContent.mInitialDisplayWidth,
                     displayContent.mInitialDisplayHeight, displayContent.mInitialDisplayDensity);
         }
+
+        try {
+            mActivityManager.updateConfiguration(null);
+        } catch (RemoteException e) {
+        }
     }
 
     public void displayReady(int displayId) {
@@ -6924,15 +6988,6 @@
                 displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
             }
         }
-
-        try {
-            mActivityManager.updateConfiguration(null);
-        } catch (RemoteException e) {
-        }
-
-        synchronized (mWindowMap) {
-            readForcedDisplaySizeAndDensityLocked(getDisplayContent(displayId));
-        }
     }
 
     public void systemReady() {
@@ -6966,7 +7021,7 @@
         public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
         public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
         public static final int WINDOW_FREEZE_TIMEOUT = 11;
-        public static final int HOLD_SCREEN_CHANGED = 12;
+
         public static final int APP_TRANSITION_TIMEOUT = 13;
         public static final int PERSIST_ANIMATION_SCALE = 14;
         public static final int FORCE_GC = 15;
@@ -6987,8 +7042,6 @@
         public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
         public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 2;
 
-        private Session mLastReportedHold;
-
         public H() {
         }
 
@@ -7240,33 +7293,6 @@
                     break;
                 }
 
-                case HOLD_SCREEN_CHANGED: {
-                    Session oldHold;
-                    Session newHold;
-                    synchronized (mWindowMap) {
-                        oldHold = mLastReportedHold;
-                        newHold = (Session)msg.obj;
-                        mLastReportedHold = newHold;
-                    }
-
-                    if (oldHold != newHold) {
-                        try {
-                            if (oldHold != null) {
-                                mBatteryStats.noteStopWakelock(oldHold.mUid, -1,
-                                        "window",
-                                        BatteryStats.WAKE_TYPE_WINDOW);
-                            }
-                            if (newHold != null) {
-                                mBatteryStats.noteStartWakelock(newHold.mUid, -1,
-                                        "window",
-                                        BatteryStats.WAKE_TYPE_WINDOW);
-                            }
-                        } catch (RemoteException e) {
-                        }
-                    }
-                    break;
-                }
-
                 case APP_TRANSITION_TIMEOUT: {
                     synchronized (mWindowMap) {
                         if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
@@ -7561,7 +7587,7 @@
         }
     }
 
-    private void rebuildBlackFrame() {
+    private void rebuildBlackFrameLocked() {
         if (mBlackFrame != null) {
             mBlackFrame.kill();
             mBlackFrame = null;
@@ -7573,6 +7599,13 @@
             int initW, initH, baseW, baseH;
             final boolean rotated = (mRotation == Surface.ROTATION_90
                     || mRotation == Surface.ROTATION_270);
+            if (DEBUG_BOOT) {
+                Slog.i(TAG, "BLACK FRAME: rotated=" + rotated + " init="
+                        + displayContent.mInitialDisplayWidth + "x"
+                        + displayContent.mInitialDisplayHeight + " base="
+                        + displayContent.mBaseDisplayWidth + "x"
+                        + displayContent.mBaseDisplayHeight);
+            }
             if (rotated) {
                 initW = displayContent.mInitialDisplayHeight;
                 initH = displayContent.mInitialDisplayWidth;
@@ -7634,7 +7667,7 @@
             }
         }
         if (changed) {
-            reconfigureDisplayLocked(displayContent);
+            rebuildBlackFrameLocked();
         }
     }
 
@@ -7663,7 +7696,7 @@
             final DisplayContent displayContent = getDisplayContent(displayId);
             setForcedDisplayDensityLocked(displayContent, density);
             Settings.Secure.putString(mContext.getContentResolver(),
-                    Settings.Secure.DISPLAY_SIZE_FORCED, Integer.toString(density));
+                    Settings.Secure.DISPLAY_DENSITY_FORCED, Integer.toString(density));
         }
     }
 
@@ -7706,7 +7739,7 @@
             mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
         }
 
-        rebuildBlackFrame();
+        rebuildBlackFrameLocked();
 
         performLayoutAndPlaceSurfacesLocked();
     }
@@ -8318,15 +8351,23 @@
             NN = mOpeningApps.size();
             for (i=0; i<NN; i++) {
                 AppWindowToken wtoken = mOpeningApps.get(i);
+                final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
-                wtoken.mAppAnimator.clearThumbnail();
+                appAnimator.clearThumbnail();
                 wtoken.reportedVisible = false;
                 wtoken.inPendingTransaction = false;
-                wtoken.mAppAnimator.animation = null;
+                appAnimator.animation = null;
                 setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
                 wtoken.updateReportedVisibilityLocked();
                 wtoken.waitingToShow = false;
-                mAnimator.mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked();
+
+                appAnimator.mAllAppWinAnimators.clear();
+                final int N = wtoken.allAppWindows.size();
+                for (int j = 0; j < N; j++) {
+                    appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
+                }
+                mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
+
                 if (animLp != null) {
                     int layer = -1;
                     for (int j=0; j<wtoken.windows.size(); j++) {
@@ -8381,7 +8422,7 @@
                     drawSurface.release();
                     topOpeningApp.mAppAnimator.thumbnailLayer = topOpeningLayer;
                     Animation anim = createThumbnailAnimationLocked(
-                            transit, true, true, mNextAppTransitionDelayed);
+                            transit, true, true, mNextAppTransitionScaleUp);
                     topOpeningApp.mAppAnimator.thumbnailAnimation = anim;
                     anim.restrictDuration(MAX_ANIMATION_DURATION);
                     anim.scaleCurrentDuration(mTransitionAnimationScale);
@@ -9065,31 +9106,25 @@
         // Finally update all input windows now that the window changes have stabilized.
         mInputMonitor.updateInputWindowsLw(true /*force*/);
 
-        setHoldScreenLocked(mInnerFields.mHoldScreen != null);
+        setHoldScreenLocked(mInnerFields.mHoldScreen);
         if (!mDisplayFrozen) {
             if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
-                mPowerManager.setScreenBrightnessOverride(-1);
+                mPowerManager.setScreenBrightnessOverrideFromWindowManager(-1);
             } else {
-                mPowerManager.setScreenBrightnessOverride((int)
-                        (mInnerFields.mScreenBrightness * PowerManager.BRIGHTNESS_ON));
+                mPowerManager.setScreenBrightnessOverrideFromWindowManager(
+                        toBrightnessOverride(mInnerFields.mScreenBrightness));
             }
             if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
-                mPowerManager.setButtonBrightnessOverride(-1);
+                mPowerManager.setButtonBrightnessOverrideFromWindowManager(-1);
             } else {
-                mPowerManager.setButtonBrightnessOverride((int)
-                        (mInnerFields.mButtonBrightness * PowerManager.BRIGHTNESS_ON));
+                mPowerManager.setButtonBrightnessOverrideFromWindowManager(
+                        toBrightnessOverride(mInnerFields.mButtonBrightness));
             }
         }
-        if (mInnerFields.mHoldScreen != mHoldingScreenOn) {
-            mHoldingScreenOn = mInnerFields.mHoldScreen;
-            Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, mInnerFields.mHoldScreen);
-            mH.sendMessage(m);
-        }
 
         if (mTurnOnScreen) {
             if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
-            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
-                    PowerManager.USER_ACTIVITY_EVENT_BUTTON, true);
+            mPowerManager.wakeUp(SystemClock.uptimeMillis());
             mTurnOnScreen = false;
         }
 
@@ -9120,6 +9155,10 @@
         }
     }
 
+    private int toBrightnessOverride(float value) {
+        return (int)(value * PowerManager.BRIGHTNESS_ON);
+    }
+
     void checkDrawnWindowsLocked() {
         if (mWaitingForDrawn.size() > 0) {
             for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
@@ -9165,13 +9204,17 @@
         }
     }
 
-    /**
-     * Must be called with the main window manager lock held.
-     */
-    void setHoldScreenLocked(boolean holding) {
-        boolean state = mHoldingScreenWakeLock.isHeld();
-        if (holding != state) {
-            if (holding) {
+    void setHoldScreenLocked(final Session newHoldScreen) {
+        final boolean hold = newHoldScreen != null;
+
+        if (hold && mHoldingScreenOn != newHoldScreen) {
+            mHoldingScreenWakeLock.setWorkSource(new WorkSource(newHoldScreen.mUid));
+        }
+        mHoldingScreenOn = newHoldScreen;
+
+        final boolean state = mHoldingScreenWakeLock.isHeld();
+        if (hold != state) {
+            if (hold) {
                 mPolicy.screenOnStartedLw();
                 mHoldingScreenWakeLock.acquire();
             } else {
@@ -9577,7 +9620,7 @@
 
             // TODO(multidisplay): rotation on main screen only.
             DisplayInfo displayInfo = getDefaultDisplayContent().getDisplayInfo();
-            mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
+            mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext, mDisplay,
                     mFxSession, inTransaction, displayInfo.logicalWidth, displayInfo.logicalHeight,
                     mDisplay.getRotation());
         }
@@ -9690,7 +9733,7 @@
             if (line != null) {
                 String[] toks = line.split("%");
                 if (toks != null && toks.length > 0) {
-                    mWatermark = new Watermark(mRealDisplayMetrics, mFxSession, toks);
+                    mWatermark = new Watermark(mDisplay, mRealDisplayMetrics, mFxSession, toks);
                 }
             }
         } catch (FileNotFoundException e) {
@@ -10149,15 +10192,15 @@
                             pw.print(" mNextAppTransitionStartHeight=");
                             pw.println(mNextAppTransitionStartHeight);
                     break;
-                case ActivityOptions.ANIM_THUMBNAIL:
-                case ActivityOptions.ANIM_THUMBNAIL_DELAYED:
+                case ActivityOptions.ANIM_THUMBNAIL_SCALE_UP:
+                case ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN:
                     pw.print("  mNextAppTransitionThumbnail=");
                             pw.print(mNextAppTransitionThumbnail);
                             pw.print(" mNextAppTransitionStartX=");
                             pw.print(mNextAppTransitionStartX);
                             pw.print(" mNextAppTransitionStartY=");
                             pw.println(mNextAppTransitionStartY);
-                    pw.print("  mNextAppTransitionDelayed="); pw.println(mNextAppTransitionDelayed);
+                    pw.print("  mNextAppTransitionScaleUp="); pw.println(mNextAppTransitionScaleUp);
                     break;
             }
             if (mNextAppTransitionCallback != null) {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 43ff3987..a52e1d7 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -22,6 +22,9 @@
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 
 import com.android.server.input.InputWindowHandle;
 
@@ -33,7 +36,9 @@
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Slog;
 import android.view.DisplayInfo;
 import android.view.Gravity;
@@ -257,6 +262,9 @@
 
     DisplayContent  mDisplayContent;
 
+    // UserId and appId of the owner. Don't display windows of non-current user.
+    final int mOwnerUid;
+
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState attachedWindow, int seq, WindowManager.LayoutParams a,
            int viewVisibility, final DisplayContent displayContent) {
@@ -264,6 +272,7 @@
         mSession = s;
         mClient = c;
         mToken = token;
+        mOwnerUid = s.mUid;
         mAttrs.copyFrom(a);
         mViewVisibility = viewVisibility;
         mDisplayContent = displayContent;
@@ -894,6 +903,11 @@
     }
 
     boolean showLw(boolean doAnimation, boolean requestAnim) {
+        if (isOtherUsersAppWindow()) {
+            Slog.w(TAG, "Current user " + mService.mCurrentUserId + " trying to display "
+                    + this + ", type " + mAttrs.type + ", belonging to " + mOwnerUid);
+            return false;
+        }
         if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
             // Already showing.
             return false;
@@ -970,6 +984,17 @@
         return mClient.asBinder().isBinderAlive();
     }
 
+    boolean isOtherUsersAppWindow() {
+        final int type = mAttrs.type;
+        if ((UserHandle.getUserId(mOwnerUid) != mService.mCurrentUserId)
+                && (mOwnerUid != Process.SYSTEM_UID)
+                && (type >= TYPE_BASE_APPLICATION) && (type <= LAST_APPLICATION_WINDOW)
+                && (type != TYPE_APPLICATION_STARTING)) {
+            return true;
+        }
+        return false;
+    }
+
     private static void applyInsets(Region outRegion, Rect frame, Rect inset) {
         outRegion.set(
                 frame.left + inset.left, frame.top + inset.top,
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index d931426..69bad81 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -474,24 +474,14 @@
         private final Point mSize = new Point();
         private final Rect mWindowCrop = new Rect();
         private boolean mShown = false;
-        private int mDisplayId;
-        private String mName = "Not named";
+        private int mLayerStack;
+        private String mName;
 
         public SurfaceTrace(SurfaceSession s,
-                       int pid, int displayId, int w, int h, int format, int flags) throws
-                       OutOfResourcesException {
-            super(s, pid, displayId, w, h, format, flags);
-            mSize.set(w, h);
-            mDisplayId = displayId;
-            Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by "
-                    + Debug.getCallers(3));
-        }
-
-        public SurfaceTrace(SurfaceSession s,
-                       int pid, String name, int displayId, int w, int h, int format, int flags)
+                       int pid, String name, int layerStack, int w, int h, int format, int flags)
                    throws OutOfResourcesException {
-            super(s, pid, name, displayId, w, h, format, flags);
-            mName = name;
+            super(s, pid, name, layerStack, w, h, format, flags);
+            mName = name != null ? name : "Not named";
             mSize.set(w, h);
             Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by "
                     + Debug.getCallers(3));
@@ -550,10 +540,10 @@
         }
 
         @Override
-        public void setDisplayId(int displayId) {
-            super.setDisplayId(displayId);
-            mDisplayId = displayId;
-            Slog.v(SURFACE_TAG, "setDisplayId: " + this + ". Called by " + Debug.getCallers(3));
+        public void setLayerStack(int layerStack) {
+            super.setLayerStack(layerStack);
+            mLayerStack = layerStack;
+            Slog.v(SURFACE_TAG, "setLayerStack: " + this + ". Called by " + Debug.getCallers(3));
         }
 
         @Override
@@ -597,7 +587,7 @@
         @Override
         public String toString() {
             return "Surface " + Integer.toHexString(System.identityHashCode(this)) + " "
-                    + mName + " (" + mDisplayId + "): shown=" + mShown + " layer=" + mLayer
+                    + mName + " (" + mLayerStack + "): shown=" + mShown + " layer=" + mLayer
                     + " alpha=" + mSurfaceTraceAlpha + " " + mPosition.x + "," + mPosition.y
                     + " " + mSize.x + "x" + mSize.y
                     + " crop=" + mWindowCrop.toShortString();
@@ -1300,6 +1290,11 @@
 
     // This must be called while inside a transaction.
     boolean performShowLocked() {
+        if (mWin.isOtherUsersAppWindow()) {
+            Slog.w(TAG, "Current user " + mService.mCurrentUserId + " trying to display "
+                    + this + ", type " + mWin.mAttrs.type + ", belonging to " + mWin.mOwnerUid);
+            return false;
+        }
         if (DEBUG_VISIBILITY || (DEBUG_STARTING_WINDOW &&
                 mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING)) {
             RuntimeException e = null;
diff --git a/services/jni/com_android_server_BatteryService.cpp b/services/jni/com_android_server_BatteryService.cpp
index ca6f206..e6133af 100644
--- a/services/jni/com_android_server_BatteryService.cpp
+++ b/services/jni/com_android_server_BatteryService.cpp
@@ -42,6 +42,7 @@
     // members
     jfieldID mAcOnline;
     jfieldID mUsbOnline;
+    jfieldID mWirelessOnline;
     jfieldID mBatteryStatus;
     jfieldID mBatteryHealth;
     jfieldID mBatteryPresent;
@@ -71,6 +72,7 @@
 struct PowerSupplyPaths {
     char* acOnlinePath;
     char* usbOnlinePath;
+    char* wirelessOnlinePath;
     char* batteryStatusPath;
     char* batteryHealthPath;
     char* batteryPresentPath;
@@ -88,8 +90,8 @@
     switch (status[0]) {
         case 'C': return gConstants.statusCharging;         // Charging
         case 'D': return gConstants.statusDischarging;      // Discharging
-        case 'F': return gConstants.statusFull;             // Not charging
-        case 'N': return gConstants.statusNotCharging;      // Full
+        case 'F': return gConstants.statusFull;             // Full
+        case 'N': return gConstants.statusNotCharging;      // Not charging
         case 'U': return gConstants.statusUnknown;          // Unknown
             
         default: {
@@ -198,6 +200,7 @@
 {
     setBooleanField(env, obj, gPaths.acOnlinePath, gFieldIds.mAcOnline);
     setBooleanField(env, obj, gPaths.usbOnlinePath, gFieldIds.mUsbOnline);
+    setBooleanField(env, obj, gPaths.wirelessOnlinePath, gFieldIds.mWirelessOnline);
     setBooleanField(env, obj, gPaths.batteryPresentPath, gFieldIds.mBatteryPresent);
     
     setIntField(env, obj, gPaths.batteryCapacityPath, gFieldIds.mBatteryLevel);
@@ -260,6 +263,11 @@
                     if (access(path, R_OK) == 0)
                         gPaths.usbOnlinePath = strdup(path);
                 }
+                else if (strcmp(buf, "Wireless") == 0) {
+                    snprintf(path, sizeof(path), "%s/%s/online", POWER_SUPPLY_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        gPaths.wirelessOnlinePath = strdup(path);
+                }
                 else if (strcmp(buf, "Battery") == 0) {
                     snprintf(path, sizeof(path), "%s/%s/status", POWER_SUPPLY_PATH, name);
                     if (access(path, R_OK) == 0)
@@ -307,6 +315,8 @@
         ALOGE("acOnlinePath not found");
     if (!gPaths.usbOnlinePath)
         ALOGE("usbOnlinePath not found");
+    if (!gPaths.wirelessOnlinePath)
+        ALOGE("wirelessOnlinePath not found");
     if (!gPaths.batteryStatusPath)
         ALOGE("batteryStatusPath not found");
     if (!gPaths.batteryHealthPath)
@@ -331,6 +341,7 @@
     
     gFieldIds.mAcOnline = env->GetFieldID(clazz, "mAcOnline", "Z");
     gFieldIds.mUsbOnline = env->GetFieldID(clazz, "mUsbOnline", "Z");
+    gFieldIds.mWirelessOnline = env->GetFieldID(clazz, "mWirelessOnline", "Z");
     gFieldIds.mBatteryStatus = env->GetFieldID(clazz, "mBatteryStatus", "I");
     gFieldIds.mBatteryHealth = env->GetFieldID(clazz, "mBatteryHealth", "I");
     gFieldIds.mBatteryPresent = env->GetFieldID(clazz, "mBatteryPresent", "Z");
@@ -341,6 +352,7 @@
 
     LOG_FATAL_IF(gFieldIds.mAcOnline == NULL, "Unable to find BatteryService.AC_ONLINE_PATH");
     LOG_FATAL_IF(gFieldIds.mUsbOnline == NULL, "Unable to find BatteryService.USB_ONLINE_PATH");
+    LOG_FATAL_IF(gFieldIds.mWirelessOnline == NULL, "Unable to find BatteryService.WIRELESS_ONLINE_PATH");
     LOG_FATAL_IF(gFieldIds.mBatteryStatus == NULL, "Unable to find BatteryService.BATTERY_STATUS_PATH");
     LOG_FATAL_IF(gFieldIds.mBatteryHealth == NULL, "Unable to find BatteryService.BATTERY_HEALTH_PATH");
     LOG_FATAL_IF(gFieldIds.mBatteryPresent == NULL, "Unable to find BatteryService.BATTERY_PRESENT_PATH");
diff --git a/services/jni/com_android_server_LightsService.cpp b/services/jni/com_android_server_LightsService.cpp
index 9ed495195..401e1aa 100644
--- a/services/jni/com_android_server_LightsService.cpp
+++ b/services/jni/com_android_server_LightsService.cpp
@@ -120,7 +120,10 @@
     state.flashOffMS = offMS;
     state.brightnessMode = brightnessMode;
 
-    devices->lights[light]->set_light(devices->lights[light], &state);
+    {
+        ALOGD_IF_SLOW(50, "Excessive delay setting light");
+        devices->lights[light]->set_light(devices->lights[light], &state);
+    }
 }
 
 static JNINativeMethod method_table[] = {
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp
index 35c2142..495d4ab 100644
--- a/services/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/jni/com_android_server_input_InputManagerService.cpp
@@ -63,7 +63,7 @@
 static struct {
     jmethodID notifyConfigurationChanged;
     jmethodID notifyInputDevicesChanged;
-    jmethodID notifyLidSwitchChanged;
+    jmethodID notifySwitch;
     jmethodID notifyInputChannelBroken;
     jmethodID notifyANR;
     jmethodID filterInputEvent;
@@ -143,7 +143,7 @@
 
 enum {
     WM_ACTION_PASS_TO_USER = 1,
-    WM_ACTION_POKE_USER_ACTIVITY = 2,
+    WM_ACTION_WAKE_UP = 2,
     WM_ACTION_GO_TO_SLEEP = 4,
 };
 
@@ -578,14 +578,9 @@
 
     JNIEnv* env = jniEnv();
 
-    switch (switchCode) {
-    case SW_LID:
-        // When switch value is set indicates lid is closed.
-        env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyLidSwitchChanged,
-                when, switchValue == 0 /*lidOpen*/);
-        checkAndClearExceptionFromCallback(env, "notifyLidSwitchChanged");
-        break;
-    }
+    env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifySwitch,
+            when, switchCode, switchValue);
+    checkAndClearExceptionFromCallback(env, "notifySwitch");
 }
 
 void NativeInputManager::notifyConfigurationChanged(nsecs_t when) {
@@ -899,11 +894,11 @@
         android_server_PowerManagerService_goToSleep(when);
     }
 
-    if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) {
+    if (wmActions & WM_ACTION_WAKE_UP) {
 #if DEBUG_INPUT_DISPATCHER_POLICY
-        ALOGD("handleInterceptActions: Poking user activity.");
+        ALOGD("handleInterceptActions: Waking up.");
 #endif
-        android_server_PowerManagerService_userActivity(when, USER_ACTIVITY_EVENT_BUTTON);
+        android_server_PowerManagerService_wakeUp(when);
     }
 
     if (wmActions & WM_ACTION_PASS_TO_USER) {
@@ -1410,8 +1405,8 @@
     GET_METHOD_ID(gServiceClassInfo.notifyInputDevicesChanged, clazz,
             "notifyInputDevicesChanged", "([Landroid/view/InputDevice;)V");
 
-    GET_METHOD_ID(gServiceClassInfo.notifyLidSwitchChanged, clazz,
-            "notifyLidSwitchChanged", "(JZ)V");
+    GET_METHOD_ID(gServiceClassInfo.notifySwitch, clazz,
+            "notifySwitch", "(JII)V");
 
     GET_METHOD_ID(gServiceClassInfo.notifyInputChannelBroken, clazz,
             "notifyInputChannelBroken", "(Lcom/android/server/input/InputWindowHandle;)V");
diff --git a/services/jni/com_android_server_power_PowerManagerService.cpp b/services/jni/com_android_server_power_PowerManagerService.cpp
index 8307d25..3f3970b 100644
--- a/services/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/jni/com_android_server_power_PowerManagerService.cpp
@@ -21,6 +21,8 @@
 #include "JNIHelp.h"
 #include "jni.h"
 
+#include <ScopedUtfChars.h>
+
 #include <limits.h>
 
 #include <android_runtime/AndroidRuntime.h>
@@ -28,6 +30,7 @@
 #include <utils/Timers.h>
 #include <utils/misc.h>
 #include <utils/String8.h>
+#include <utils/Log.h>
 #include <hardware/power.h>
 #include <hardware_legacy/power.h>
 #include <cutils/android_reboot.h>
@@ -42,8 +45,9 @@
 // ----------------------------------------------------------------------------
 
 static struct {
-    jmethodID goToSleep;
-    jmethodID userActivity;
+    jmethodID wakeUpFromNative;
+    jmethodID goToSleepFromNative;
+    jmethodID userActivityFromNative;
 } gPowerManagerServiceClassInfo;
 
 // ----------------------------------------------------------------------------
@@ -106,9 +110,21 @@
 
         JNIEnv* env = AndroidRuntime::getJNIEnv();
 
-        env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.userActivity,
-                nanoseconds_to_milliseconds(eventTime), false, eventType, false);
-        checkAndClearExceptionFromCallback(env, "userActivity");
+        env->CallVoidMethod(gPowerManagerServiceObj,
+                gPowerManagerServiceClassInfo.userActivityFromNative,
+                nanoseconds_to_milliseconds(eventTime), eventType, 0);
+        checkAndClearExceptionFromCallback(env, "userActivityFromNative");
+    }
+}
+
+void android_server_PowerManagerService_wakeUp(nsecs_t eventTime) {
+    if (gPowerManagerServiceObj) {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+        env->CallVoidMethod(gPowerManagerServiceObj,
+                gPowerManagerServiceClassInfo.wakeUpFromNative,
+                nanoseconds_to_milliseconds(eventTime));
+        checkAndClearExceptionFromCallback(env, "wakeUpFromNative");
     }
 }
 
@@ -116,9 +132,10 @@
     if (gPowerManagerServiceObj) {
         JNIEnv* env = AndroidRuntime::getJNIEnv();
 
-        env->CallVoidMethod(gPowerManagerServiceObj, gPowerManagerServiceClassInfo.goToSleep,
-                nanoseconds_to_milliseconds(eventTime));
-        checkAndClearExceptionFromCallback(env, "goToSleep");
+        env->CallVoidMethod(gPowerManagerServiceObj,
+                gPowerManagerServiceClassInfo.goToSleepFromNative,
+                nanoseconds_to_milliseconds(eventTime), 0);
+        checkAndClearExceptionFromCallback(env, "goToSleepFromNative");
     }
 }
 
@@ -137,68 +154,62 @@
 }
 
 static void nativeSetPowerState(JNIEnv* env,
-        jobject serviceObj, jboolean screenOn, jboolean screenBright) {
+        jclass clazz, jboolean screenOn, jboolean screenBright) {
     AutoMutex _l(gPowerManagerLock);
     gScreenOn = screenOn;
     gScreenBright = screenBright;
 }
 
-static void nativeStartSurfaceFlingerAnimation(JNIEnv* env,
-        jobject obj, jint mode) {
-    // this is not handled by surfaceflinger anymore
+static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
+    ScopedUtfChars name(env, nameStr);
+    acquire_wake_lock(PARTIAL_WAKE_LOCK, name.c_str());
 }
 
-static void nativeAcquireWakeLock(JNIEnv *env, jobject clazz, jint lock, jstring idObj) {
-    if (idObj == NULL) {
-        jniThrowNullPointerException(env, "id is null");
-        return;
-    }
-
-    const char *id = env->GetStringUTFChars(idObj, NULL);
-
-    acquire_wake_lock(lock, id);
-
-    env->ReleaseStringUTFChars(idObj, id);
+static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass clazz, jstring nameStr) {
+    ScopedUtfChars name(env, nameStr);
+    release_wake_lock(name.c_str());
 }
 
-static void nativeReleaseWakeLock(JNIEnv *env, jobject clazz, jstring idObj) {
-    if (idObj == NULL) {
-        jniThrowNullPointerException(env, "id is null");
-        return ;
-    }
-
-    const char *id = env->GetStringUTFChars(idObj, NULL);
-
-    release_wake_lock(id);
-
-    env->ReleaseStringUTFChars(idObj, id);
-
-}
-
-static int nativeSetScreenState(JNIEnv *env, jobject clazz, jboolean on) {
+static void nativeSetScreenState(JNIEnv *env, jclass clazz, jboolean on) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (on) {
-        autosuspend_disable();
+        {
+            ALOGD_IF_SLOW(50, "Excessive delay in autosuspend_disable() while turning screen on");
+            autosuspend_disable();
+        }
+
         if (gPowerModule) {
+            ALOGD_IF_SLOW(10, "Excessive delay in setInteractive(true) while turning screen on");
             gPowerModule->setInteractive(gPowerModule, true);
         }
-        s->unblank();
+
+        {
+            ALOGD_IF_SLOW(20, "Excessive delay in unblank() while turning screen on");
+            s->unblank();
+        }
     } else {
-        s->blank();
+        {
+            ALOGD_IF_SLOW(20, "Excessive delay in blank() while turning screen off");
+            s->blank();
+        }
+
         if (gPowerModule) {
+            ALOGD_IF_SLOW(10, "Excessive delay in setInteractive(false) while turning screen off");
             gPowerModule->setInteractive(gPowerModule, false);
         }
-        autosuspend_enable();
-    }
 
-    return 0;
+        {
+            ALOGD_IF_SLOW(50, "Excessive delay in autosuspend_enable() while turning screen off");
+            autosuspend_enable();
+        }
+    }
 }
 
-static void nativeShutdown(JNIEnv *env, jobject clazz) {
+static void nativeShutdown(JNIEnv *env, jclass clazz) {
     android_reboot(ANDROID_RB_POWEROFF, 0, 0);
 }
 
-static void nativeReboot(JNIEnv *env, jobject clazz, jstring reason) {
+static void nativeReboot(JNIEnv *env, jclass clazz, jstring reason) {
     if (reason == NULL) {
         android_reboot(ANDROID_RB_RESTART, 0, 0);
     } else {
@@ -218,13 +229,11 @@
             (void*) nativeInit },
     { "nativeSetPowerState", "(ZZ)V",
             (void*) nativeSetPowerState },
-    { "nativeStartSurfaceFlingerAnimation", "(I)V",
-            (void*) nativeStartSurfaceFlingerAnimation },
-    { "nativeAcquireWakeLock", "(ILjava/lang/String;)V",
-            (void*) nativeAcquireWakeLock },
-    { "nativeReleaseWakeLock", "(Ljava/lang/String;)V",
-            (void*) nativeReleaseWakeLock },
-    { "nativeSetScreenState", "(Z)I",
+    { "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
+            (void*) nativeAcquireSuspendBlocker },
+    { "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
+            (void*) nativeReleaseSuspendBlocker },
+    { "nativeSetScreenState", "(Z)V",
             (void*) nativeSetScreenState },
     { "nativeShutdown", "()V",
             (void*) nativeShutdown },
@@ -254,11 +263,14 @@
     jclass clazz;
     FIND_CLASS(clazz, "com/android/server/power/PowerManagerService");
 
-    GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleep, clazz,
-            "goToSleep", "(J)V");
+    GET_METHOD_ID(gPowerManagerServiceClassInfo.wakeUpFromNative, clazz,
+            "wakeUpFromNative", "(J)V");
 
-    GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivity, clazz,
-            "userActivity", "(JZIZ)V");
+    GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleepFromNative, clazz,
+            "goToSleepFromNative", "(JI)V");
+
+    GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz,
+            "userActivityFromNative", "(JII)V");
 
     // Initialize
     for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) {
diff --git a/services/jni/com_android_server_power_PowerManagerService.h b/services/jni/com_android_server_power_PowerManagerService.h
index cc3b5ef5..0808b80 100644
--- a/services/jni/com_android_server_power_PowerManagerService.h
+++ b/services/jni/com_android_server_power_PowerManagerService.h
@@ -27,6 +27,7 @@
 extern bool android_server_PowerManagerService_isScreenOn();
 extern bool android_server_PowerManagerService_isScreenBright();
 extern void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType);
+extern void android_server_PowerManagerService_wakeUp(nsecs_t eventTime);
 extern void android_server_PowerManagerService_goToSleep(nsecs_t eventTime);
 
 } // namespace android
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 3f66de6..8aeb2af 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -33,7 +33,9 @@
     <uses-permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING" />
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
-
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    
     <application>
         <uses-library android:name="android.test.runner" />
 
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index f6f9aa0..3373fd4 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -71,7 +71,7 @@
 import android.os.INetworkManagementService;
 import android.os.IPowerManager;
 import android.os.MessageQueue.IdleHandler;
-import android.os.UserId;
+import android.os.UserHandle;
 import android.test.AndroidTestCase;
 import android.test.mock.MockPackageManager;
 import android.test.suitebuilder.annotation.LargeTest;
@@ -138,10 +138,10 @@
     private static final int APP_ID_A = android.os.Process.FIRST_APPLICATION_UID + 800;
     private static final int APP_ID_B = android.os.Process.FIRST_APPLICATION_UID + 801;
 
-    private static final int UID_A = UserId.getUid(USER_ID, APP_ID_A);
-    private static final int UID_B = UserId.getUid(USER_ID, APP_ID_B);
-    private static final int UID_A_GUEST = UserId.getUid(USER_ID_GUEST, APP_ID_A);
-    private static final int UID_B_GUEST = UserId.getUid(USER_ID_GUEST, APP_ID_B);
+    private static final int UID_A = UserHandle.getUid(USER_ID, APP_ID_A);
+    private static final int UID_B = UserHandle.getUid(USER_ID, APP_ID_B);
+    private static final int UID_A_GUEST = UserHandle.getUid(USER_ID_GUEST, APP_ID_A);
+    private static final int UID_B_GUEST = UserHandle.getUid(USER_ID_GUEST, APP_ID_B);
 
     private static final int PID_1 = 400;
     private static final int PID_2 = 401;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index bc3649c..59a86c2 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -16,35 +16,23 @@
 
 package com.android.server.pm;
 
-import com.android.server.pm.UserManagerService;
-
+import android.content.Context;
 import android.content.pm.UserInfo;
 import android.os.Debug;
 import android.os.Environment;
+import android.os.UserManager;
 import android.test.AndroidTestCase;
 
 import java.util.List;
 
-/** Test {@link UserManagerService} functionality. */
+/** Test {@link UserManager} functionality. */
 public class UserManagerTest extends AndroidTestCase {
 
-    UserManagerService mUserManager = null;
+    UserManager mUserManager = null;
 
     @Override
     public void setUp() throws Exception {
-        mUserManager = new UserManagerService(Environment.getExternalStorageDirectory(),
-                Environment.getExternalStorageDirectory());
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        List<UserInfo> users = mUserManager.getUsers();
-        // Remove all except the primary user
-        for (UserInfo user : users) {
-            if (!user.isPrimary()) {
-                mUserManager.removeUser(user.id);
-            }
-        }
+        mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
     }
 
     public void testHasPrimary() throws Exception {
@@ -52,12 +40,10 @@
     }
 
     public void testAddUser() throws Exception {
-        final UserManagerService details = mUserManager;
-
-        UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST);
+        UserInfo userInfo = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST);
         assertTrue(userInfo != null);
 
-        List<UserInfo> list = details.getUsers();
+        List<UserInfo> list = mUserManager.getUsers();
         boolean found = false;
         for (UserInfo user : list) {
             if (user.id == userInfo.id && user.name.equals("Guest 1")
@@ -68,13 +54,12 @@
             }
         }
         assertTrue(found);
+        mUserManager.removeUser(userInfo.id);
     }
 
     public void testAdd2Users() throws Exception {
-        final UserManagerService details = mUserManager;
-
-        UserInfo user1 = details.createUser("Guest 1", UserInfo.FLAG_GUEST);
-        UserInfo user2 = details.createUser("User 2", UserInfo.FLAG_ADMIN);
+        UserInfo user1 = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST);
+        UserInfo user2 = mUserManager.createUser("User 2", UserInfo.FLAG_ADMIN);
 
         assertTrue(user1 != null);
         assertTrue(user2 != null);
@@ -82,14 +67,14 @@
         assertTrue(findUser(0));
         assertTrue(findUser(user1.id));
         assertTrue(findUser(user2.id));
+        mUserManager.removeUser(user1.id);
+        mUserManager.removeUser(user2.id);
     }
 
     public void testRemoveUser() throws Exception {
-        final UserManagerService details = mUserManager;
+        UserInfo userInfo = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST);
 
-        UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST);
-
-        details.removeUser(userInfo.id);
+        mUserManager.removeUser(userInfo.id);
 
         assertFalse(findUser(userInfo.id));
     }
@@ -104,4 +89,18 @@
         }
         return false;
     }
+
+    public void testSerialNumber() {
+        UserInfo user1 = mUserManager.createUser("User 1", UserInfo.FLAG_RESTRICTED);
+        int serialNumber1 = user1.serialNumber;
+        assertEquals(serialNumber1, mUserManager.getUserSerialNumber(user1.id));
+        assertEquals(user1.id, mUserManager.getUserHandle(serialNumber1));
+        mUserManager.removeUser(user1.id);
+        UserInfo user2 = mUserManager.createUser("User 2", UserInfo.FLAG_RESTRICTED);
+        int serialNumber2 = user2.serialNumber;
+        assertFalse(serialNumber1 == serialNumber2);
+        assertEquals(serialNumber2, mUserManager.getUserSerialNumber(user2.id));
+        assertEquals(user2.id, mUserManager.getUserHandle(serialNumber2));
+        mUserManager.removeUser(user2.id);
+    }
 }
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 677f713..078699f 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -87,6 +87,22 @@
     }
 
     /**
+     * Initialize from the SignalStrength structure.
+     *
+     * @param ss
+     *
+     * @hide
+     */
+    public void initialize(SignalStrength ss, int timingAdvance) {
+        mSignalStrength = ss.getLteSignalStrenght();
+        mRsrp = ss.getLteRsrp();
+        mRsrq = ss.getLteRsrq();
+        mRssnr = ss.getLteRssnr();
+        mCqi = ss.getLteCqi();
+        mTimingAdvance = timingAdvance;
+    }
+
+    /**
      * @hide
      */
     protected void copyFrom(CellSignalStrengthLte s) {
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index d0a2e11..f998935 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -47,7 +47,8 @@
     };
 
     /** @hide */
-    public static final int INVALID_SNR = 0x7FFFFFFF;
+    //Use int max, as -1 is a valid value in signal strength
+    public static final int INVALID = 0x7FFFFFFF;
 
     private int mGsmSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
     private int mGsmBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
@@ -95,15 +96,39 @@
         mEvdoDbm = -1;
         mEvdoEcio = -1;
         mEvdoSnr = -1;
-        mLteSignalStrength = -1;
-        mLteRsrp = -1;
-        mLteRsrq = -1;
-        mLteRssnr = INVALID_SNR;
-        mLteCqi = -1;
+        mLteSignalStrength = 99;
+        mLteRsrp = INVALID;
+        mLteRsrq = INVALID;
+        mLteRssnr = INVALID;
+        mLteCqi = INVALID;
         isGsm = true;
     }
 
     /**
+     * This constructor is used to create SignalStrength with default
+     * values and set the isGsmFlag with the value passed in the input
+     *
+     * @param gsmFlag true if Gsm Phone,false if Cdma phone
+     * @return newly created SignalStrength
+     * @hide
+     */
+    public SignalStrength(boolean gsmFlag) {
+        mGsmSignalStrength = 99;
+        mGsmBitErrorRate = -1;
+        mCdmaDbm = -1;
+        mCdmaEcio = -1;
+        mEvdoDbm = -1;
+        mEvdoEcio = -1;
+        mEvdoSnr = -1;
+        mLteSignalStrength = 99;
+        mLteRsrp = INVALID;
+        mLteRsrq = INVALID;
+        mLteRssnr = INVALID;
+        mLteCqi = INVALID;
+        isGsm = gsmFlag;
+    }
+
+    /**
      * Constructor
      *
      * @hide
@@ -112,10 +137,10 @@
             int cdmaDbm, int cdmaEcio,
             int evdoDbm, int evdoEcio, int evdoSnr,
             int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
-            boolean gsm) {
+            boolean gsmFlag) {
         initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
                 evdoDbm, evdoEcio, evdoSnr, lteSignalStrength, lteRsrp,
-                lteRsrq, lteRssnr, lteCqi, gsm);
+                lteRsrq, lteRssnr, lteCqi, gsmFlag);
     }
 
     /**
@@ -126,10 +151,10 @@
     public SignalStrength(int gsmSignalStrength, int gsmBitErrorRate,
             int cdmaDbm, int cdmaEcio,
             int evdoDbm, int evdoEcio, int evdoSnr,
-            boolean gsm) {
+            boolean gsmFlag) {
         initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
-                evdoDbm, evdoEcio, evdoSnr, -1, -1,
-                -1, INVALID_SNR, -1, gsm);
+                evdoDbm, evdoEcio, evdoSnr, 99, INVALID,
+                INVALID, INVALID, INVALID, gsmFlag);
     }
 
     /**
@@ -162,8 +187,8 @@
             int evdoDbm, int evdoEcio, int evdoSnr,
             boolean gsm) {
         initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
-                evdoDbm, evdoEcio, evdoSnr, -1, -1,
-                -1, INVALID_SNR, -1, gsm);
+                evdoDbm, evdoEcio, evdoSnr, 99, INVALID,
+                INVALID, INVALID, INVALID, gsm);
     }
 
     /**
@@ -231,6 +256,8 @@
      * @hide
      */
     public SignalStrength(Parcel in) {
+        if (DBG) log("Size of signalstrength parcel:" + in.dataSize());
+
         mGsmSignalStrength = in.readInt();
         mGsmBitErrorRate = in.readInt();
         mCdmaDbm = in.readInt();
@@ -288,7 +315,54 @@
     };
 
     /**
-     * Get the GSM Signal Strength, valid values are (0-31, 99) as defined in TS 27.007 8.5
+     * Validate the individual signal strength fields as per the range
+     * specified in ril.h
+     * Set to invalid any field that is not in the valid range
+     * Cdma, evdo, lte rsrp & rsrq values are sign converted
+     * when received from ril interface
+     *
+     * @return
+     *      Valid values for all signalstrength fields
+     * @hide
+     */
+    public void validateInput() {
+        if (DBG) log("Signal before validate=" + this);
+        // TS 27.007 8.5
+        mGsmSignalStrength = mGsmSignalStrength >= 0 ? mGsmSignalStrength : 99;
+        // BER no change;
+
+        mCdmaDbm = mCdmaDbm > 0 ? -mCdmaDbm : -120;
+        mCdmaEcio = (mCdmaEcio > 0) ? -mCdmaEcio : -160;
+
+        mEvdoDbm = (mEvdoDbm > 0) ? -mEvdoDbm : -120;
+        mEvdoEcio = (mEvdoEcio > 0) ? -mEvdoEcio : -1;
+        mEvdoSnr = ((mEvdoSnr > 0) && (mEvdoSnr <= 8)) ? mEvdoSnr : -1;
+
+        // TS 36.214 Physical Layer Section 5.1.3, TS 36.331 RRC
+        mLteSignalStrength = (mLteSignalStrength >= 0) ? mLteSignalStrength : 99;
+        mLteRsrp = ((mLteRsrp >= 44) && (mLteRsrp <= 140)) ? -mLteRsrp : SignalStrength.INVALID;
+        mLteRsrq = ((mLteRsrq >= 3) && (mLteRsrq <= 20)) ? -mLteRsrq : SignalStrength.INVALID;
+        mLteRssnr = ((mLteRssnr >= -200) && (mLteRssnr <= 300)) ? mLteRssnr
+                : SignalStrength.INVALID;
+        // Cqi no change
+        if (DBG) log("Signal after validate=" + this);
+    }
+
+    /**
+     * @param true - Gsm, Lte phones
+     *        false - Cdma phones
+     *
+     * Used by voice phone to set the isGsm
+     *        flag
+     * @hide
+     */
+    public void setGsm(boolean gsmFlag) {
+        isGsm = gsmFlag;
+    }
+
+    /**
+     * Get the GSM Signal Strength, valid values are (0-31, 99) as defined in TS
+     * 27.007 8.5
      */
     public int getGsmSignalStrength() {
         return this.mGsmSignalStrength;
@@ -336,6 +410,31 @@
         return this.mEvdoSnr;
     }
 
+    /** @hide */
+    public int getLteSignalStrenght() {
+        return mLteSignalStrength;
+    }
+
+    /** @hide */
+    public int getLteRsrp() {
+        return mLteRsrp;
+    }
+
+    /** @hide */
+    public int getLteRsrq() {
+        return mLteRsrq;
+    }
+
+    /** @hide */
+    public int getLteRssnr() {
+        return mLteRssnr;
+    }
+
+    /** @hide */
+    public int getLteCqi() {
+        return mLteCqi;
+    }
+
     /**
      * Get signal level as an int from 0..4
      *
@@ -345,25 +444,19 @@
         int level;
 
         if (isGsm) {
-            // TODO Need solve the discrepancy of invalid values between
-            // RIL_LTE_SignalStrength and here.
-            if ((mLteSignalStrength == -1)
-                    && (mLteRsrp == -1)
-                    && (mLteRsrq == -1)
-                    && (mLteCqi == -1)) {
+            level = getLteLevel();
+            if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
                 level = getGsmLevel();
-            } else {
-                level = getLteLevel();
             }
         } else {
             int cdmaLevel = getCdmaLevel();
             int evdoLevel = getEvdoLevel();
             if (evdoLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
                 /* We don't know evdo, use cdma */
-                level = getCdmaLevel();
+                level = cdmaLevel;
             } else if (cdmaLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
                 /* We don't know cdma, use evdo */
-                level = getEvdoLevel();
+                level = evdoLevel;
             } else {
                 /* We know both, use the lowest level */
                 level = cdmaLevel < evdoLevel ? cdmaLevel : evdoLevel;
@@ -381,10 +474,7 @@
     public int getAsuLevel() {
         int asuLevel;
         if (isGsm) {
-            if ((mLteSignalStrength == -1)
-                    && (mLteRsrp == -1)
-                    && (mLteRsrq == -1)
-                    && (mLteCqi == -1)) {
+            if (getLteLevel() == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
                 asuLevel = getGsmAsuLevel();
             } else {
                 asuLevel = getLteAsuLevel();
@@ -416,16 +506,17 @@
         int dBm;
 
         if(isGsm()) {
-            if ((mLteSignalStrength == -1)
-                    && (mLteRsrp == -1)
-                    && (mLteRsrq == -1)
-                    && (mLteCqi == -1)) {
+            if (getLteLevel() == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
                 dBm = getGsmDbm();
             } else {
                 dBm = getLteDbm();
             }
         } else {
-            dBm = getCdmaDbm();
+            int cdmaDbm = getCdmaDbm();
+            int evdoDbm = getEvdoDbm();
+
+            return (evdoDbm == -120) ? cdmaDbm : ((cdmaDbm == -120) ? evdoDbm
+                    : (cdmaDbm < evdoDbm ? cdmaDbm : evdoDbm));
         }
         if (DBG) log("getDbm=" + dBm);
         return dBm;
@@ -620,34 +711,63 @@
      * @hide
      */
     public int getLteLevel() {
-        int levelLteRsrp = 0;
-        int levelLteRssnr = 0;
+        /*
+         * TS 36.214 Physical Layer Section 5.1.3 TS 36.331 RRC RSSI = received
+         * signal + noise RSRP = reference signal dBm RSRQ = quality of signal
+         * dB= Number of Resource blocksxRSRP/RSSI SNR = gain=signal/noise ratio
+         * = -10log P1/P2 dB
+         */
+        int rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, rsrpIconLevel = -1, snrIconLevel = -1;
 
-        if (mLteRsrp == -1) levelLteRsrp = 0;
-        else if (mLteRsrp >= -95) levelLteRsrp = SIGNAL_STRENGTH_GREAT;
-        else if (mLteRsrp >= -105) levelLteRsrp = SIGNAL_STRENGTH_GOOD;
-        else if (mLteRsrp >= -115) levelLteRsrp = SIGNAL_STRENGTH_MODERATE;
-        else levelLteRsrp = SIGNAL_STRENGTH_POOR;
+        if (mLteRsrp > -44) rsrpIconLevel = -1;
+        else if (mLteRsrp >= -85) rsrpIconLevel = SIGNAL_STRENGTH_GREAT;
+        else if (mLteRsrp >= -95) rsrpIconLevel = SIGNAL_STRENGTH_GOOD;
+        else if (mLteRsrp >= -105) rsrpIconLevel = SIGNAL_STRENGTH_MODERATE;
+        else if (mLteRsrp >= -115) rsrpIconLevel = SIGNAL_STRENGTH_POOR;
+        else if (mLteRsrp >= -140) rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
 
-        if (mLteRssnr == INVALID_SNR) levelLteRssnr = 0;
-        else if (mLteRssnr >= 45) levelLteRssnr = SIGNAL_STRENGTH_GREAT;
-        else if (mLteRssnr >= 10) levelLteRssnr = SIGNAL_STRENGTH_GOOD;
-        else if (mLteRssnr >= -30) levelLteRssnr = SIGNAL_STRENGTH_MODERATE;
-        else levelLteRssnr = SIGNAL_STRENGTH_POOR;
+        /*
+         * Values are -200 dB to +300 (SNR*10dB) RS_SNR >= 13.0 dB =>4 bars 4.5
+         * dB <= RS_SNR < 13.0 dB => 3 bars 1.0 dB <= RS_SNR < 4.5 dB => 2 bars
+         * -3.0 dB <= RS_SNR < 1.0 dB 1 bar RS_SNR < -3.0 dB/No Service Antenna
+         * Icon Only
+         */
+        if (mLteRssnr > 300) snrIconLevel = -1;
+        else if (mLteRssnr >= 130) snrIconLevel = SIGNAL_STRENGTH_GREAT;
+        else if (mLteRssnr >= 45) snrIconLevel = SIGNAL_STRENGTH_GOOD;
+        else if (mLteRssnr >= 10) snrIconLevel = SIGNAL_STRENGTH_MODERATE;
+        else if (mLteRssnr >= -30) snrIconLevel = SIGNAL_STRENGTH_POOR;
+        else if (mLteRssnr >= -200)
+            snrIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
 
-        int level;
-        if (mLteRsrp == -1)
-            level = levelLteRssnr;
-        else if (mLteRssnr == INVALID_SNR)
-            level = levelLteRsrp;
-        else
-            level = (levelLteRssnr < levelLteRsrp) ? levelLteRssnr : levelLteRsrp;
+        if (DBG) log("getLTELevel - rsrp:" + mLteRsrp + " snr:" + mLteRssnr + " rsrpIconLevel:"
+                + rsrpIconLevel + " snrIconLevel:" + snrIconLevel);
 
-        if (DBG) log("Lte rsrp level: "+levelLteRsrp
-                + " snr level: " + levelLteRssnr + " level: " + level);
-        return level;
+        /* Choose a measurement type to use for notification */
+        if (snrIconLevel != -1 && rsrpIconLevel != -1) {
+            /*
+             * The number of bars displayed shall be the smaller of the bars
+             * associated with LTE RSRP and the bars associated with the LTE
+             * RS_SNR
+             */
+            return (rsrpIconLevel < snrIconLevel ? rsrpIconLevel : snrIconLevel);
+        }
+
+        if (snrIconLevel != -1) return snrIconLevel;
+
+        if (rsrpIconLevel != -1) return rsrpIconLevel;
+
+        /* Valid values are (0-63, 99) as defined in TS 36.331 */
+        if (mLteSignalStrength > 63) rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        else if (mLteSignalStrength >= 12) rssiIconLevel = SIGNAL_STRENGTH_GREAT;
+        else if (mLteSignalStrength >= 8) rssiIconLevel = SIGNAL_STRENGTH_GOOD;
+        else if (mLteSignalStrength >= 5) rssiIconLevel = SIGNAL_STRENGTH_MODERATE;
+        else if (mLteSignalStrength >= 0) rssiIconLevel = SIGNAL_STRENGTH_POOR;
+        if (DBG) log("getLTELevel - rssi:" + mLteSignalStrength + " rssiIconLevel:"
+                + rssiIconLevel);
+        return rssiIconLevel;
+
     }
-
     /**
      * Get the LTE signal level as an asu value between 0..97, 99 is unknown
      * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
@@ -657,8 +777,20 @@
     public int getLteAsuLevel() {
         int lteAsuLevel = 99;
         int lteDbm = getLteDbm();
-        if (lteDbm <= -140) lteAsuLevel = 0;
-        else if (lteDbm >= -43) lteAsuLevel = 97;
+        /*
+         * 3GPP 27.007 (Ver 10.3.0) Sec 8.69
+         * 0   -140 dBm or less
+         * 1   -139 dBm
+         * 2...96  -138... -44 dBm
+         * 97  -43 dBm or greater
+         * 255 not known or not detectable
+         */
+        /*
+         * validateInput will always give a valid range between -140 t0 -44 as
+         * per ril.h. so RSRP >= -43 & <-140 will fall under asu level 255
+         * and not 97 or 0
+         */
+        if (lteDbm == SignalStrength.INVALID) lteAsuLevel = 255;
         else lteAsuLevel = lteDbm + 140;
         if (DBG) log("Lte Asu level: "+lteAsuLevel);
         return lteAsuLevel;
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 9acffa3..12ad4fea 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -28,6 +28,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.res.AssetManager;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
@@ -37,6 +38,8 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.UserHandle;
+import android.view.CompatibilityInfoHolder;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -303,12 +306,12 @@
     }
 
     @Override
-    public void sendBroadcastToUser(Intent intent, int userId) {
+    public void sendBroadcastAsUser(Intent intent, UserHandle user) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public void sendOrderedBroadcastToUser(Intent intent, int userId,
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
             BroadcastReceiver resultReceiver, Handler scheduler,
             int initialCode, String initialData, Bundle initialExtras) {
         throw new UnsupportedOperationException();
@@ -477,7 +480,18 @@
     }
 
     @Override
+    public Context createConfigurationContext(Configuration overrideConfiguration) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public boolean isRestricted() {
         throw new UnsupportedOperationException();        
     }
+
+    /** @hide */
+    @Override
+    public CompatibilityInfoHolder getCompatibilityInfo() {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index ef14404..0fb51f0 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -39,6 +39,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
+import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -479,7 +480,8 @@
      * @hide - to match hiding in superclass
      */
     @Override
-    public void getPackageSizeInfo(String packageName, IPackageStatsObserver observer) {
+    public void getPackageSizeInfo(String packageName, int userHandle,
+            IPackageStatsObserver observer) {
         throw new UnsupportedOperationException();
     }
 
@@ -519,6 +521,16 @@
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public void installPackageWithVerificationAndEncryption(Uri packageURI,
+            IPackageInstallObserver observer, int flags, String installerPackageName,
+            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public void verifyPendingInstall(int id, int verificationCode) {
         throw new UnsupportedOperationException();
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index 0ec1f13..9599b19 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -30,6 +30,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.graphics.Bitmap;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -40,12 +41,16 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.util.Log;
 
 public class ActivityTestMain extends Activity {
     static final String TAG = "ActivityTest";
 
+    static final String KEY_CONFIGURATION = "configuration";
+
     ActivityManager mAm;
+    Configuration mOverrideConfig;
 
     class BroadcastResultReceiver extends BroadcastReceiver {
         @Override
@@ -111,6 +116,12 @@
         super.onCreate(savedInstanceState);
 
         mAm = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
+        if (savedInstanceState != null) {
+            mOverrideConfig = savedInstanceState.getParcelable(KEY_CONFIGURATION);
+            if (mOverrideConfig != null) {
+                applyOverrideConfiguration(mOverrideConfig);
+            }
+        }
     }
 
     @Override
@@ -177,11 +188,26 @@
         menu.add("Send to user 1!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
             @Override public boolean onMenuItemClick(MenuItem item) {
                 Intent intent = new Intent(ActivityTestMain.this, UserTarget.class);
-                sendOrderedBroadcastToUser(intent, 1, new BroadcastResultReceiver(), 
+                sendOrderedBroadcastAsUser(intent, new UserHandle(1), new BroadcastResultReceiver(), 
                         null, Activity.RESULT_OK, null, null);
                 return true;
             }
         });
+        menu.add("Density!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+            @Override public boolean onMenuItemClick(MenuItem item) {
+                if (mOverrideConfig == null) {
+                    mOverrideConfig = new Configuration();
+                }
+                if (mOverrideConfig.densityDpi == Configuration.DENSITY_DPI_UNDEFINED) {
+                    mOverrideConfig.densityDpi = (getApplicationContext().getResources()
+                            .getConfiguration().densityDpi*2)/3;
+                } else {
+                    mOverrideConfig.densityDpi = Configuration.DENSITY_DPI_UNDEFINED;
+                }
+                recreate();
+                return true;
+            }
+        });
         return true;
     }
 
@@ -191,6 +217,14 @@
         buildUi();
     }
 
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        if (mOverrideConfig != null) {
+            outState.putParcelable(KEY_CONFIGURATION, mOverrideConfig);
+        }
+    }
+
     private View scrollWrap(View view) {
         ScrollView scroller = new ScrollView(this);
         scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT,
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/SingleUserProvider.java b/tests/ActivityTests/src/com/google/android/test/activity/SingleUserProvider.java
index 83785e4..1e7b8f4 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/SingleUserProvider.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/SingleUserProvider.java
@@ -21,7 +21,7 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.Process;
+import android.os.UserHandle;
 
 public class SingleUserProvider extends ContentProvider {
     static final String AUTHORITY = "com.google.android.test.activity.single_user";
@@ -60,7 +60,7 @@
     @Override
     public Bundle call(String method, String arg, Bundle extras) {
         Bundle res = new Bundle();
-        res.putInt("user", Process.myUserHandle());
+        res.putInt("user", UserHandle.myUserId());
         return res;
     }
 }
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/SingleUserReceiver.java b/tests/ActivityTests/src/com/google/android/test/activity/SingleUserReceiver.java
index 9295cf48..8afa478 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/SingleUserReceiver.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/SingleUserReceiver.java
@@ -21,12 +21,13 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Process;
+import android.os.UserHandle;
 
 public class SingleUserReceiver extends BroadcastReceiver {
     @Override
     public void onReceive(Context context, Intent intent) {
         Bundle res = getResultExtras(true);
-        res.putInt("user", Process.myUserHandle());
+        res.putInt("user", UserHandle.myUserId());
         setResultExtras(res);
     }
 }
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/UserTarget.java b/tests/ActivityTests/src/com/google/android/test/activity/UserTarget.java
index 9c6a9f1..47539a1 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/UserTarget.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/UserTarget.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Process;
+import android.os.UserHandle;
 import android.util.Log;
 
 public class UserTarget extends BroadcastReceiver {
@@ -28,7 +29,7 @@
     public void onReceive(Context context, Intent intent) {
         Log.i("ActivityTest", "Received: " + intent);
         Bundle res = getResultExtras(true);
-        res.putInt("user", Process.myUserHandle());
+        res.putInt("user", UserHandle.myUserId());
         setResultExtras(res);
     }
 }
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 1857033..c783ad6 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -177,6 +177,15 @@
         </activity>
 
         <activity
+                android:name="GlyphCacheActivity"
+                android:label="_GlyphCache">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="CanvasTextureViewActivity"
                 android:label="_CanvasTextureView">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GlyphCacheActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GlyphCacheActivity.java
new file mode 100644
index 0000000..e89b294
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GlyphCacheActivity.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import static android.widget.LinearLayout.LayoutParams;
+
+public class GlyphCacheActivity extends Activity {
+
+    private static final String mCharacterSet = "abcdefghijklmnopqrstuvwxyz" +
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "~!@#$%^&*()_+-={}[]:\";'<>?,./";
+    private int mTotalChars = 0;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        ScrollView scrollView = new ScrollView(this);
+        scrollView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT));
+        LinearLayout layout = new LinearLayout(this);
+        layout.setOrientation(LinearLayout.VERTICAL);
+        layout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+        scrollView.addView(layout);
+
+        while (mTotalChars < 10000) {
+            layout.addView(createTextView());
+        }
+        setContentView(scrollView);
+    }
+
+    private TextView createTextView() {
+        TextView textview = new TextView(this);
+        textview.setTextSize(6 + (int) (Math.random() * 5) * 10);
+        textview.setTextColor(0xff << 24 | (int) (Math.random() * 255) << 16 |
+                (int) (Math.random() * 255) << 8 | (int) (Math.random() * 255) << 16);
+        textview.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+        int numChars = 5 + (int) (Math.random() * 10);
+        mTotalChars += numChars;
+        textview.setText(createString(numChars));
+
+        return textview;
+    }
+
+    private String createString(int length) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < length; i++) {
+            sb.append(mCharacterSet.charAt((int)(Math.random() * mCharacterSet.length())));
+        }
+        return sb.toString();
+    }
+}
diff --git a/tests/MemoryUsage/Android.mk b/tests/MemoryUsage/Android.mk
new file mode 100644
index 0000000..e7bfb4f
--- /dev/null
+++ b/tests/MemoryUsage/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := MemoryUsage
+
+LOCAL_SDK_VERSION := 7
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/tests/MemoryUsage/AndroidManifest.xml b/tests/MemoryUsage/AndroidManifest.xml
new file mode 100644
index 0000000..3932e5b
--- /dev/null
+++ b/tests/MemoryUsage/AndroidManifest.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.tests.memoryusage">
+    <instrumentation android:label="Memory usage instrumentation"
+                     android:name="com.android.tests.memoryusage.MemoryUsageInstrumentation"
+                     android:targetPackage="com.android.tests.memoryusage" />
+
+    <application android:label="Memory Usage Test">
+        <uses-library android:name="android.test.runner" />
+    </application>
+</manifest>
\ No newline at end of file
diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageInstrumentation.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageInstrumentation.java
new file mode 100644
index 0000000..ed6d7e6
--- /dev/null
+++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageInstrumentation.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tests.memoryusage;
+
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+
+/**
+ * InstrumentationTestRunner for use with the {@link MemoryUsageTest}.
+ */
+public class MemoryUsageInstrumentation extends InstrumentationTestRunner {
+
+    private Bundle arguments;
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        this.arguments = arguments;
+        super.onCreate(arguments);
+    }
+
+    public Bundle getBundle() {
+        return arguments;
+    }
+
+}
diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
new file mode 100644
index 0000000..f26edc6
--- /dev/null
+++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.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 com.android.tests.memoryusage;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessErrorStateInfo;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.Debug.MemoryInfo;
+import android.test.InstrumentationTestCase;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This test is intended to measure the amount of memory applications use when
+ * they start. Names of the applications are passed in command line, and the
+ * test starts each application, waits until its memory usage is stabilized and
+ * reports the total PSS in kilobytes of each processes.
+ * The instrumentation expects the following key to be passed on the command line:
+ * apps - A list of applications to start and their corresponding result keys
+ * in the following format:
+ * -e apps <app name>^<result key>|<app name>^<result key>
+ */
+public class MemoryUsageTest extends InstrumentationTestCase {
+
+    private static final int SLEEP_TIME = 1000;
+    private static final int THRESHOLD = 1024;
+    private static final int MAX_ITERATIONS = 10;
+    private static final int MIN_ITERATIONS = 4;
+
+    private static final String TAG = "MemoryUsageInstrumentation";
+    private static final String KEY_APPS = "apps";
+
+    private Map<String, Intent> nameToIntent;
+    private Map<String, String> nameToProcess;
+    private Map<String, String> nameToResultKey;
+
+    public void testMemory() {
+        MemoryUsageInstrumentation instrumentation =
+                    (MemoryUsageInstrumentation) getInstrumentation();
+        Bundle args = instrumentation.getBundle();
+
+        createMappings();
+        parseArgs(args);
+
+        Bundle results = new Bundle();
+        for (String app : nameToResultKey.keySet()) {
+            String processName;
+            try {
+                processName = startApp(app);
+                measureMemory(app, processName, results);
+            } catch (NameNotFoundException e) {
+                Log.i(TAG, "Application " + app + " not found");
+            }
+
+        }
+        instrumentation.sendStatus(0, results);
+    }
+
+    private void parseArgs(Bundle args) {
+        nameToResultKey = new HashMap<String, String>();
+        String appList = args.getString(KEY_APPS);
+
+        if (appList == null)
+            return;
+
+        String appNames[] = appList.split("\\|");
+        for (String pair : appNames) {
+            String[] parts = pair.split("\\^");
+            if (parts.length != 2) {
+                Log.e(TAG, "The apps key is incorectly formatted");
+                fail();
+            }
+
+            nameToResultKey.put(parts[0], parts[1]);
+        }
+    }
+
+    private void createMappings() {
+        nameToIntent = new HashMap<String, Intent>();
+        nameToProcess = new HashMap<String, String>();
+
+        PackageManager pm = getInstrumentation().getContext()
+                .getPackageManager();
+        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+        intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
+        List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
+        if (ris == null || ris.isEmpty()) {
+            Log.i(TAG, "Could not find any apps");
+        } else {
+            for (ResolveInfo ri : ris) {
+                Log.i(TAG, "Name: " + ri.loadLabel(pm).toString()
+                        + " package: " + ri.activityInfo.packageName
+                        + " name: " + ri.activityInfo.name);
+                Intent startIntent = new Intent(intentToResolve);
+                startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+                startIntent.setClassName(ri.activityInfo.packageName,
+                        ri.activityInfo.name);
+                nameToIntent.put(ri.loadLabel(pm).toString(), startIntent);
+                nameToProcess.put(ri.loadLabel(pm).toString(),
+                        ri.activityInfo.processName);
+            }
+        }
+    }
+
+    private String startApp(String appName) throws NameNotFoundException {
+        Log.i(TAG, "Starting " + appName);
+
+        if (!nameToProcess.containsKey(appName))
+            throw new NameNotFoundException("Could not find: " + appName);
+
+        String process = nameToProcess.get(appName);
+        Intent startIntent = nameToIntent.get(appName);
+        getInstrumentation().getContext().startActivity(startIntent);
+        return process;
+    }
+
+    private void measureMemory(String appName, String processName,
+            Bundle results) {
+        List<Integer> pssData = new ArrayList<Integer>();
+        int pss = 0;
+        int iteration = 0;
+        while (iteration < MAX_ITERATIONS) {
+            sleep();
+            pss = getPss(processName);
+            Log.i(TAG, appName + "=" + pss);
+            if (pss < 0) {
+                reportError(appName, processName, results);
+                return;
+            }
+            pssData.add(pss);
+            if (iteration >= MIN_ITERATIONS && stabilized(pssData)) {
+                results.putInt(nameToResultKey.get(appName), pss);
+                return;
+            }
+            iteration++;
+        }
+
+        Log.w(TAG, appName + " memory usage did not stabilize");
+        results.putInt(appName, average(pssData));
+    }
+
+    private int average(List<Integer> pssData) {
+        int sum = 0;
+        for (int sample : pssData) {
+            sum += sample;
+        }
+
+        return sum / pssData.size();
+    }
+
+    private boolean stabilized(List<Integer> pssData) {
+        if (pssData.size() < 3)
+            return false;
+        int diff1 = Math.abs(pssData.get(pssData.size() - 1) - pssData.get(pssData.size() - 2));
+        int diff2 = Math.abs(pssData.get(pssData.size() - 2) - pssData.get(pssData.size() - 3));
+
+        Log.i(TAG, "diff1=" + diff1 + " diff2=" + diff2);
+
+        return (diff1 + diff2) < THRESHOLD;
+    }
+
+    private void sleep() {
+        try {
+            Thread.sleep(SLEEP_TIME);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+    }
+
+    private void reportError(String appName, String processName, Bundle results) {
+        ActivityManager am = (ActivityManager) getInstrumentation()
+                .getContext().getSystemService(Context.ACTIVITY_SERVICE);
+        List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState();
+        if (crashes != null) {
+            for (ProcessErrorStateInfo crash : crashes) {
+                if (!crash.processName.equals(processName))
+                    continue;
+
+                Log.w(TAG, appName + " crashed: " + crash.shortMsg);
+                results.putString(nameToResultKey.get(appName), crash.shortMsg);
+                return;
+            }
+        }
+
+        results.putString(nameToResultKey.get(appName),
+                "Crashed for unknown reason");
+        Log.w(TAG, appName
+                + " not found in process list, most likely it is crashed");
+    }
+
+    private int getPss(String processName) {
+        ActivityManager am = (ActivityManager) getInstrumentation()
+                .getContext().getSystemService(Context.ACTIVITY_SERVICE);
+        List<RunningAppProcessInfo> apps = am.getRunningAppProcesses();
+
+        for (RunningAppProcessInfo proc : apps) {
+            if (!proc.processName.equals(processName)) {
+                continue;
+            }
+
+            int[] pids = {
+                proc.pid };
+
+            MemoryInfo meminfo = am.getProcessMemoryInfo(pids)[0];
+            return meminfo.getTotalPss();
+
+        }
+        return -1;
+    }
+}
diff --git a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsView.java b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsView.java
index b3b3756..041782d 100644
--- a/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsView.java
+++ b/tests/RenderScriptTests/Balls/src/com/example/android/rs/balls/BallsView.java
@@ -105,7 +105,7 @@
     }
 
     void setAccel(float x, float y, float z) {
-        if (mRender == null) {
+        if ((mRender == null) || (mRS == null)) {
             return;
         }
         mRender.setAccel(x, -y);
diff --git a/tests/RenderScriptTests/ComputeBenchmark/Android.mk b/tests/RenderScriptTests/ComputeBenchmark/Android.mk
new file mode 100644
index 0000000..8d47e89
--- /dev/null
+++ b/tests/RenderScriptTests/ComputeBenchmark/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+                   $(call all-renderscript-files-under, src)
+
+LOCAL_PACKAGE_NAME := RsComputeBenchmark
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/ComputeBenchmark/AndroidManifest.xml b/tests/RenderScriptTests/ComputeBenchmark/AndroidManifest.xml
new file mode 100644
index 0000000..c8fcc17
--- /dev/null
+++ b/tests/RenderScriptTests/ComputeBenchmark/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.android.rs.computebench">
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-sdk android:minSdkVersion="17" />
+    <application android:label="_RS_Compute_Bench">
+        <activity android:name="ComputeBench">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RenderScriptTests/ComputeBenchmark/res/layout/main.xml b/tests/RenderScriptTests/ComputeBenchmark/res/layout/main.xml
new file mode 100644
index 0000000..9e9dab8
--- /dev/null
+++ b/tests/RenderScriptTests/ComputeBenchmark/res/layout/main.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+    <ImageView
+        android:id="@+id/displayin"
+        android:layout_width="320dip"
+        android:layout_height="266dip" />
+
+    <ImageView
+        android:id="@+id/displayout"
+        android:layout_width="320dip"
+        android:layout_height="266dip" />
+
+</LinearLayout>
diff --git a/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/Benchmark.java b/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/Benchmark.java
new file mode 100644
index 0000000..ec80719
--- /dev/null
+++ b/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/Benchmark.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.rs.computebench;
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class Benchmark implements Runnable {
+    private final RenderScript mRS;
+    private ScriptC_compute_benchmark mScript;
+
+    public Benchmark(RenderScript rs, Resources res) {
+        mRS = rs;
+        mScript = new ScriptC_compute_benchmark(mRS, res, R.raw.compute_benchmark);
+    }
+
+    public void run() {
+        long t = java.lang.System.currentTimeMillis();
+        mScript.invoke_bench();
+        mRS.finish();
+        t = java.lang.System.currentTimeMillis() - t;
+        android.util.Log.v("ComputeBench", "Total benchmark took " + t + " ms");
+    }
+
+}
diff --git a/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/ComputeBench.java b/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/ComputeBench.java
new file mode 100644
index 0000000..2d3e843
--- /dev/null
+++ b/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/ComputeBench.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.rs.computebench;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.renderscript.RenderScript;
+
+public class ComputeBench extends Activity {
+    private RenderScript mRS;
+    private Benchmark mBenchmark;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+
+        mRS = RenderScript.create(this);
+
+        mBenchmark = new Benchmark(mRS, getResources());
+        mBenchmark.run();
+    }
+}
diff --git a/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/compute_benchmark.rs b/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/compute_benchmark.rs
new file mode 100644
index 0000000..7b8ec04
--- /dev/null
+++ b/tests/RenderScriptTests/ComputeBenchmark/src/com/example/android/rs/computebench/compute_benchmark.rs
@@ -0,0 +1,408 @@
+// Copyright (C) 2012 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.computebench)
+
+// Test configuration (accessible from Java)
+uint priming_runs   = 1000000;
+uint timing_runs    = 5000000;
+
+// Reused variables
+
+static volatile int64_t bench_time;
+static float inv_timing_runs;
+
+#define DECL_VAR_SET(prefix)                \
+static volatile float prefix##_f_1 = 1;     \
+static volatile float2 prefix##_f_2 = 1;    \
+static volatile float3 prefix##_f_3 = 1;    \
+static volatile float4 prefix##_f_4 = 1;    \
+static volatile char prefix##_c_1 = 1;      \
+static volatile char2 prefix##_c_2 = 1;     \
+static volatile char3 prefix##_c_3 = 1;     \
+static volatile char4 prefix##_c_4 = 1;     \
+static volatile uchar prefix##_uc_1 = 1;    \
+static volatile uchar2 prefix##_uc_2 = 1;   \
+static volatile uchar3 prefix##_uc_3 = 1;   \
+static volatile uchar4 prefix##_uc_4 = 1;   \
+static volatile short prefix##_s_1 = 1;     \
+static volatile short2 prefix##_s_2 = 1;    \
+static volatile short3 prefix##_s_3 = 1;    \
+static volatile short4 prefix##_s_4 = 1;    \
+static volatile ushort prefix##_us_1 = 1;   \
+static volatile ushort2 prefix##_us_2 = 1;  \
+static volatile ushort3 prefix##_us_3 = 1;  \
+static volatile ushort4 prefix##_us_4 = 1;  \
+static volatile int prefix##_i_1 = 1;       \
+static volatile int2 prefix##_i_2 = 1;      \
+static volatile int3 prefix##_i_3 = 1;      \
+static volatile int4 prefix##_i_4 = 1;      \
+static volatile uint prefix##_ui_1 = 1;     \
+static volatile uint2 prefix##_ui_2 = 1;    \
+static volatile uint3 prefix##_ui_3 = 1;    \
+static volatile uint4 prefix##_ui_4 = 1;    \
+static volatile long prefix##_l_1 = 1;      \
+static volatile long2 prefix##_l_2 = 1;     \
+static volatile long3 prefix##_l_3 = 1;     \
+static volatile long4 prefix##_l_4 = 1;     \
+static volatile ulong prefix##_ul_1 = 1;    \
+static volatile ulong2 prefix##_ul_2 = 1;   \
+static volatile ulong3 prefix##_ul_3 = 1;   \
+static volatile ulong4 prefix##_ul_4 = 1;   \
+
+DECL_VAR_SET(res)
+DECL_VAR_SET(src1)
+DECL_VAR_SET(src2)
+DECL_VAR_SET(src3)
+
+
+// Testing macros
+
+#define RUN_BENCH(line, op)                         \
+    for (int i = priming_runs - 1; i >= 0; --i) {   \
+        line;                                       \
+    }                                               \
+    bench_time = rsUptimeMillis();                  \
+    for (int i = timing_runs - 1; i >= 0; --i) {    \
+        line;                                       \
+    }                                               \
+    bench_time = rsUptimeMillis() - bench_time;     \
+    rsDebug("    " op " took ns", (float)bench_time * inv_timing_runs);
+
+#define BENCH_BASIC_OP_TYPE(op, type)                                                               \
+    RUN_BENCH(res_##type##_1 = src1_##type##_1 op src2_##type##_1, #type "1 " #op " " #type "1")    \
+    RUN_BENCH(res_##type##_2 = src1_##type##_2 op src2_##type##_2, #type "2 " #op " " #type "2")    \
+    RUN_BENCH(res_##type##_3 = src1_##type##_3 op src2_##type##_3, #type "3 " #op " " #type "3")    \
+    RUN_BENCH(res_##type##_4 = src1_##type##_4 op src2_##type##_4, #type "4 " #op " " #type "4")    \
+
+#define BENCH_BASIC_INT_OP(op)                                  \
+    rsDebug("Testing basic operation " #op, 0);                 \
+    BENCH_BASIC_OP_TYPE(op, c)                                  \
+    BENCH_BASIC_OP_TYPE(op, uc)                                 \
+    BENCH_BASIC_OP_TYPE(op, s)                                  \
+    BENCH_BASIC_OP_TYPE(op, us)                                 \
+    BENCH_BASIC_OP_TYPE(op, i)                                  \
+    BENCH_BASIC_OP_TYPE(op, ui)                                 \
+    RUN_BENCH(res_l_1 = src1_l_1 op src2_l_1, "l1 " #op " l1")  \
+    RUN_BENCH(res_ul_1 = src1_ul_1 op src2_ul_1, "ul1 " #op " ul1")
+
+#define BENCH_BASIC_OP(op)      \
+    BENCH_BASIC_INT_OP(op)      \
+    BENCH_BASIC_OP_TYPE(op, f)
+
+#define BENCH_CVT(to, from, type)                                                                           \
+    rsDebug("Testing convert from " #from " to " #to, 0);                                                   \
+    RUN_BENCH(res_##to##_1 = (type)src1_##from##_1, "(" #to ")" #from)                                      \
+    RUN_BENCH(res_##to##_2 = convert_##type##2(src1_##from##_2), #to "2 convert_" #type "2(" #from "2)")    \
+    RUN_BENCH(res_##to##_3 = convert_##type##3(src1_##from##_3), #to "3 convert_" #type "3(" #from "3)")    \
+    RUN_BENCH(res_##to##_4 = convert_##type##4(src1_##from##_4), #to "4 convert_" #type "4(" #from "4)")
+
+#define BENCH_CVT_MATRIX(to, type)  \
+    BENCH_CVT(to, c, type);         \
+    BENCH_CVT(to, uc, type);        \
+    BENCH_CVT(to, s, type);         \
+    BENCH_CVT(to, us, type);        \
+    BENCH_CVT(to, i, type);         \
+    BENCH_CVT(to, ui, type);        \
+    BENCH_CVT(to, f, type);         \
+
+#define BENCH_XN_FUNC_YN(typeout, fnc, typein)                                                  \
+    RUN_BENCH(res_##typeout##_1 = fnc(src1_##typein##_1);, #typeout "1 " #fnc "(" #typein "1)") \
+    RUN_BENCH(res_##typeout##_2 = fnc(src1_##typein##_2);, #typeout "2 " #fnc "(" #typein "2)") \
+    RUN_BENCH(res_##typeout##_3 = fnc(src1_##typein##_3);, #typeout "3 " #fnc "(" #typein "3)") \
+    RUN_BENCH(res_##typeout##_4 = fnc(src1_##typein##_4);, #typeout "4 " #fnc "(" #typein "4)")
+
+#define BENCH_XN_FUNC_XN_XN(type, fnc)                                                                              \
+    RUN_BENCH(res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1), #type "1 " #fnc "(" #type "1, " #type "1)")   \
+    RUN_BENCH(res_##type##_2 = fnc(src1_##type##_2, src2_##type##_2), #type "2 " #fnc "(" #type "2, " #type "2)")   \
+    RUN_BENCH(res_##type##_3 = fnc(src1_##type##_3, src2_##type##_3), #type "3 " #fnc "(" #type "3, " #type "3)")   \
+    RUN_BENCH(res_##type##_4 = fnc(src1_##type##_4, src2_##type##_4), #type "4 " #fnc "(" #type "4, " #type "4)")   \
+
+#define BENCH_X_FUNC_X_X_X(type, fnc)   \
+    RUN_BENCH(res_##type##_1 = fnc(src1_##type##_1, src2_##type##_1, src3_##type##_1), #type "1 " #fnc "(" #type "1, " #type "1, " #type "1)")
+
+#define BENCH_IN_FUNC_IN(fnc)       \
+    rsDebug("Testing " #fnc, 0);    \
+    BENCH_XN_FUNC_YN(uc, fnc, uc)   \
+    BENCH_XN_FUNC_YN(c, fnc, c)     \
+    BENCH_XN_FUNC_YN(us, fnc, us)   \
+    BENCH_XN_FUNC_YN(s, fnc, s)     \
+    BENCH_XN_FUNC_YN(ui, fnc, ui)   \
+    BENCH_XN_FUNC_YN(i, fnc, i)
+
+#define BENCH_UIN_FUNC_IN(fnc)      \
+    rsDebug("Testing " #fnc, 0);    \
+    BENCH_XN_FUNC_YN(uc, fnc, c)    \
+    BENCH_XN_FUNC_YN(us, fnc, s)    \
+    BENCH_XN_FUNC_YN(ui, fnc, i)    \
+
+#define BENCH_IN_FUNC_IN_IN(fnc)    \
+    rsDebug("Testing " #fnc, 0);    \
+    BENCH_XN_FUNC_XN_XN(uc, fnc)    \
+    BENCH_XN_FUNC_XN_XN(c, fnc)     \
+    BENCH_XN_FUNC_XN_XN(us, fnc)    \
+    BENCH_XN_FUNC_XN_XN(s, fnc)     \
+    BENCH_XN_FUNC_XN_XN(ui, fnc)    \
+    BENCH_XN_FUNC_XN_XN(i, fnc)
+
+#define BENCH_I_FUNC_I_I_I(fnc)     \
+    rsDebug("Testing " #fnc, 0);    \
+    BENCH_X_FUNC_X_X_X(uc, fnc)     \
+    BENCH_X_FUNC_X_X_X(c, fnc)      \
+    BENCH_X_FUNC_X_X_X(us, fnc)     \
+    BENCH_X_FUNC_X_X_X(s, fnc)      \
+    BENCH_X_FUNC_X_X_X(ui, fnc)     \
+    BENCH_X_FUNC_X_X_X(i, fnc)
+
+#define BENCH_FN_FUNC_FN(fnc)                               \
+    rsDebug("Testing " #fnc, 0);                            \
+    RUN_BENCH(res_f_1 = fnc(src1_f_1), "f1 " #fnc "(f1)")   \
+    RUN_BENCH(res_f_2 = fnc(src1_f_2), "f2 " #fnc "(f2)")   \
+    RUN_BENCH(res_f_3 = fnc(src1_f_3), "f3 " #fnc "(f3)")   \
+    RUN_BENCH(res_f_4 = fnc(src1_f_4), "f4 " #fnc "(f4)")
+
+#define BENCH_FN_FUNC_FN_PFN(fnc)                                                   \
+    rsDebug("Testing " #fnc, 0);                                                    \
+    RUN_BENCH(res_f_1 = fnc(src1_f_1, (float*) &src2_f_1), "f1 " #fnc "(f1, f1*)")  \
+    RUN_BENCH(res_f_2 = fnc(src1_f_2, (float2*) &src2_f_2), "f2 " #fnc "(f2, f2*)") \
+    RUN_BENCH(res_f_3 = fnc(src1_f_3, (float3*) &src2_f_3), "f3 " #fnc "(f3, f3*)") \
+    RUN_BENCH(res_f_4 = fnc(src1_f_4, (float4*) &src2_f_4), "f4 " #fnc "(f4, f4*)")
+
+#define BENCH_FN_FUNC_FN_FN(fnc)                                        \
+    rsDebug("Testing " #fnc, 0);                                        \
+    RUN_BENCH(res_f_1 = fnc(src1_f_1, src2_f_1), "f1 " #fnc "(f1, f1)") \
+    RUN_BENCH(res_f_2 = fnc(src1_f_2, src2_f_2), "f2 " #fnc "(f2, f2)") \
+    RUN_BENCH(res_f_3 = fnc(src1_f_3, src2_f_3), "f3 " #fnc "(f3, f3)") \
+    RUN_BENCH(res_f_4 = fnc(src1_f_4, src2_f_4), "f4 " #fnc "(f4, f4)")
+
+#define BENCH_F34_FUNC_F34_F34(fnc)                                     \
+    rsDebug("Testing " #fnc, 0);                                        \
+    RUN_BENCH(res_f_3 = fnc(src1_f_3, src2_f_3), "f3 " #fnc "(f3, f3)") \
+    RUN_BENCH(res_f_4 = fnc(src1_f_4, src2_f_4), "f4 " #fnc "(f4, f4)")
+
+#define BENCH_FN_FUNC_FN_F(fnc)                                         \
+    rsDebug("Testing " #fnc, 0);                                        \
+    RUN_BENCH(res_f_1 = fnc(src1_f_1, src2_f_1), "f1 " #fnc "(f1, f1)") \
+    RUN_BENCH(res_f_2 = fnc(src1_f_2, src2_f_1), "f2 " #fnc "(f2, f1)") \
+    RUN_BENCH(res_f_3 = fnc(src1_f_3, src2_f_1), "f3 " #fnc "(f3, f1)") \
+    RUN_BENCH(res_f_4 = fnc(src1_f_4, src2_f_1), "f4 " #fnc "(f4, f1)")
+
+#define BENCH_F_FUNC_FN(fnc)                                \
+    rsDebug("Testing " #fnc, 0);                            \
+    RUN_BENCH(res_f_1 = fnc(src1_f_1), "f1 " #fnc "(f1)")   \
+    RUN_BENCH(res_f_1 = fnc(src1_f_2), "f1 " #fnc "(f2)")   \
+    RUN_BENCH(res_f_1 = fnc(src1_f_3), "f1 " #fnc "(f3)")   \
+    RUN_BENCH(res_f_1 = fnc(src1_f_4), "f1 " #fnc "(f4)")
+
+#define BENCH_F_FUNC_FN_FN(fnc)                                         \
+    rsDebug("Testing " #fnc, 0);                                        \
+    RUN_BENCH(res_f_1 = fnc(src1_f_1, src2_f_1), "f1 " #fnc "(f1, f1)") \
+    RUN_BENCH(res_f_1 = fnc(src1_f_2, src2_f_2), "f1 " #fnc "(f2, f2)") \
+    RUN_BENCH(res_f_1 = fnc(src1_f_3, src2_f_3), "f1 " #fnc "(f3, f3)") \
+    RUN_BENCH(res_f_1 = fnc(src1_f_4, src2_f_4), "f1 " #fnc "(f4, f4)")
+
+#define BENCH_FN_FUNC_FN_IN(fnc)                                        \
+    rsDebug("Testing " #fnc, 0);                                        \
+    RUN_BENCH(res_f_1 = fnc(src1_f_1, src1_i_1), "f1 " #fnc "(f1, i1)") \
+    RUN_BENCH(res_f_2 = fnc(src1_f_2, src1_i_2), "f2 " #fnc "(f2, i2)") \
+    RUN_BENCH(res_f_3 = fnc(src1_f_3, src1_i_3), "f3 " #fnc "(f3, i3)") \
+    RUN_BENCH(res_f_4 = fnc(src1_f_4, src1_i_4), "f4 " #fnc "(f4, i4)")
+
+#define BENCH_FN_FUNC_FN_I(fnc)                                         \
+    rsDebug("Testing " #fnc, 0);                                        \
+    RUN_BENCH(res_f_1 = fnc(src1_f_1, src1_i_1), "f1 " #fnc "(f1, i1)") \
+    RUN_BENCH(res_f_2 = fnc(src1_f_2, src1_i_1), "f2 " #fnc "(f2, i1)") \
+    RUN_BENCH(res_f_3 = fnc(src1_f_3, src1_i_1), "f3 " #fnc "(f3, i1)") \
+    RUN_BENCH(res_f_4 = fnc(src1_f_4, src1_i_1), "f4 " #fnc "(f4, i1)")
+
+#define BENCH_FN_FUNC_FN_FN_FN(fnc)                                                     \
+    rsDebug("Testing " #fnc, 0);                                                        \
+    RUN_BENCH(res_f_1 = fnc(src1_f_1, src2_f_1, src3_f_1), "f1 " #fnc "(f1, f1, f1)")   \
+    RUN_BENCH(res_f_2 = fnc(src1_f_2, src2_f_2, src3_f_2), "f2 " #fnc "(f2, f2, f2)")   \
+    RUN_BENCH(res_f_3 = fnc(src1_f_3, src2_f_3, src3_f_3), "f3 " #fnc "(f3, f3, f3)")   \
+    RUN_BENCH(res_f_4 = fnc(src1_f_4, src2_f_4, src3_f_4), "f4 " #fnc "(f4, f4, f4)")
+
+#define BENCH_FN_FUNC_FN_FN_F(fnc)                                                      \
+    rsDebug("Testing " #fnc, 0);                                                        \
+    RUN_BENCH(res_f_1 = fnc(src1_f_1, src2_f_1, src3_f_1), "f1 " #fnc "(f1, f1, f1)")   \
+    RUN_BENCH(res_f_2 = fnc(src1_f_2, src2_f_2, src3_f_1), "f2 " #fnc "(f2, f2, f1)")   \
+    RUN_BENCH(res_f_3 = fnc(src1_f_3, src2_f_3, src3_f_1), "f3 " #fnc "(f3, f3, f1)")   \
+    RUN_BENCH(res_f_4 = fnc(src1_f_4, src2_f_4, src3_f_1), "f4 " #fnc "(f4, f4, f1)")
+
+#define BENCH_FN_FUNC_FN_PIN(fnc)                                                   \
+    rsDebug("Testing " #fnc, 0);                                                    \
+    RUN_BENCH(res_f_1 = fnc(src1_f_1, (int*) &src1_i_1), "f1 " #fnc "(f1, i1*)")    \
+    RUN_BENCH(res_f_2 = fnc(src1_f_2, (int2*) &src1_i_2), "f2 " #fnc "(f2, i2*)")   \
+    RUN_BENCH(res_f_3 = fnc(src1_f_3, (int3*) &src1_i_3), "f3 " #fnc "(f3, i3*)")   \
+    RUN_BENCH(res_f_4 = fnc(src1_f_4, (int4*) &src1_i_4), "f4 " #fnc "(f4, i4*)")
+
+#define BENCH_FN_FUNC_FN_FN_PIN(fnc)                                                            \
+    rsDebug("Testing " #fnc, 0);                                                                \
+    RUN_BENCH(res_f_1 = fnc(src1_f_1, src2_f_1, (int*) &src1_i_1), "f1 " #fnc "(f1, f1, i1*)")  \
+    RUN_BENCH(res_f_2 = fnc(src1_f_2, src2_f_2, (int2*) &src1_i_2), "f2 " #fnc "(f2, f2, i2*)") \
+    RUN_BENCH(res_f_3 = fnc(src1_f_3, src2_f_3, (int3*) &src1_i_3), "f3 " #fnc "(f3, f3, i3*)") \
+    RUN_BENCH(res_f_4 = fnc(src1_f_4, src2_f_4, (int4*) &src1_i_4), "f4 " #fnc "(f4, f4, i4*)")
+
+#define BENCH_IN_FUNC_FN(fnc)                               \
+    rsDebug("Testing " #fnc, 0);                            \
+    RUN_BENCH(res_i_1 = fnc(src1_f_1), "i1 " #fnc "(f1)")   \
+    RUN_BENCH(res_i_2 = fnc(src1_f_2), "i2 " #fnc "(f2)")   \
+    RUN_BENCH(res_i_3 = fnc(src1_f_3), "i3 " #fnc "(f3)")   \
+    RUN_BENCH(res_i_4 = fnc(src1_f_4), "i4 " #fnc "(f4)")
+
+
+// Testing functions
+
+static void bench_basic_operators() {
+    int i = 0;
+    BENCH_BASIC_OP(+);
+    BENCH_BASIC_OP(-);
+    BENCH_BASIC_OP(*);
+    BENCH_BASIC_OP(/);
+    BENCH_BASIC_INT_OP(%);
+    BENCH_BASIC_INT_OP(<<);
+    BENCH_BASIC_INT_OP(>>);
+}
+
+static void bench_convert() {
+    BENCH_CVT_MATRIX(c, char);
+    BENCH_CVT_MATRIX(uc, uchar);
+    BENCH_CVT_MATRIX(s, short);
+    BENCH_CVT_MATRIX(us, ushort);
+    BENCH_CVT_MATRIX(i, int);
+    BENCH_CVT_MATRIX(ui, uint);
+    BENCH_CVT_MATRIX(f, float);
+}
+
+static void bench_int_math() {
+    BENCH_UIN_FUNC_IN(abs);
+    BENCH_IN_FUNC_IN(clz);
+    BENCH_IN_FUNC_IN_IN(min);
+    BENCH_IN_FUNC_IN_IN(max);
+    BENCH_I_FUNC_I_I_I(rsClamp);
+}
+
+static void bench_fp_math() {
+    BENCH_FN_FUNC_FN(acos);
+    BENCH_FN_FUNC_FN(acosh);
+    BENCH_FN_FUNC_FN(acospi);
+    BENCH_FN_FUNC_FN(asin);
+    BENCH_FN_FUNC_FN(asinh);
+    BENCH_FN_FUNC_FN(asinpi);
+    BENCH_FN_FUNC_FN(atan);
+    BENCH_FN_FUNC_FN_FN(atan2);
+    BENCH_FN_FUNC_FN(atanh);
+    BENCH_FN_FUNC_FN(atanpi);
+    BENCH_FN_FUNC_FN_FN(atan2pi);
+    BENCH_FN_FUNC_FN(cbrt);
+    BENCH_FN_FUNC_FN(ceil);
+    BENCH_FN_FUNC_FN_FN_FN(clamp);
+    BENCH_FN_FUNC_FN_FN_F(clamp);
+    BENCH_FN_FUNC_FN_FN(copysign);
+    BENCH_FN_FUNC_FN(cos);
+    BENCH_FN_FUNC_FN(cosh);
+    BENCH_FN_FUNC_FN(cospi);
+    BENCH_F34_FUNC_F34_F34(cross);
+    BENCH_FN_FUNC_FN(degrees);
+    BENCH_F_FUNC_FN_FN(distance);
+    BENCH_F_FUNC_FN_FN(dot);
+    BENCH_FN_FUNC_FN(erfc);
+    BENCH_FN_FUNC_FN(erf);
+    BENCH_FN_FUNC_FN(exp);
+    BENCH_FN_FUNC_FN(exp2);
+    BENCH_FN_FUNC_FN(exp10);
+    BENCH_FN_FUNC_FN(expm1);
+    BENCH_FN_FUNC_FN(fabs);
+    BENCH_FN_FUNC_FN_FN(fdim);
+    BENCH_FN_FUNC_FN(floor);
+    BENCH_FN_FUNC_FN_FN_FN(fma);
+    BENCH_FN_FUNC_FN_FN(fmax);
+    BENCH_FN_FUNC_FN_F(fmax);
+    BENCH_FN_FUNC_FN_FN(fmin);
+    BENCH_FN_FUNC_FN_F(fmin);
+    BENCH_FN_FUNC_FN_FN(fmod);
+    BENCH_FN_FUNC_FN_PFN(fract);
+    BENCH_FN_FUNC_FN_PIN(frexp);
+    BENCH_FN_FUNC_FN_FN(hypot);
+    BENCH_IN_FUNC_FN(ilogb);
+    BENCH_FN_FUNC_FN_IN(ldexp);
+    BENCH_FN_FUNC_FN_I(ldexp);
+    BENCH_F_FUNC_FN(length);
+    BENCH_FN_FUNC_FN(lgamma);
+    BENCH_FN_FUNC_FN_PIN(lgamma);
+    BENCH_FN_FUNC_FN(log);
+    BENCH_FN_FUNC_FN(log2);
+    BENCH_FN_FUNC_FN(log10);
+    BENCH_FN_FUNC_FN(log1p);
+    BENCH_FN_FUNC_FN(logb);
+    BENCH_FN_FUNC_FN_FN_FN(mad);
+    BENCH_FN_FUNC_FN_FN(max);
+    BENCH_FN_FUNC_FN_F(max);
+    BENCH_FN_FUNC_FN_FN(min);
+    BENCH_FN_FUNC_FN_F(min);
+    BENCH_FN_FUNC_FN_FN_FN(mix);
+    BENCH_FN_FUNC_FN_FN_F(mix);
+    BENCH_FN_FUNC_FN_PFN(modf);
+    BENCH_FN_FUNC_FN_FN(nextafter);
+    BENCH_FN_FUNC_FN(normalize);
+    BENCH_FN_FUNC_FN_FN(pow);
+    BENCH_FN_FUNC_FN_IN(pown);
+    BENCH_FN_FUNC_FN_FN(powr);
+    BENCH_FN_FUNC_FN(radians);
+    BENCH_FN_FUNC_FN_FN(remainder);
+    BENCH_FN_FUNC_FN_FN_PIN(remquo);
+    BENCH_FN_FUNC_FN(rint);
+    BENCH_FN_FUNC_FN_IN(rootn);
+    BENCH_FN_FUNC_FN(round);
+    BENCH_FN_FUNC_FN(rsqrt);
+    BENCH_FN_FUNC_FN(sign);
+    BENCH_FN_FUNC_FN(sin);
+    BENCH_FN_FUNC_FN_PFN(sincos);
+    BENCH_FN_FUNC_FN(sinh);
+    BENCH_FN_FUNC_FN(sinpi);
+    BENCH_FN_FUNC_FN(sqrt);
+    BENCH_FN_FUNC_FN_FN(step);
+    BENCH_FN_FUNC_FN_F(step);
+    BENCH_FN_FUNC_FN(tan);
+    BENCH_FN_FUNC_FN(tanh);
+    BENCH_FN_FUNC_FN(tanpi);
+    BENCH_FN_FUNC_FN(tgamma);
+    BENCH_FN_FUNC_FN(trunc);
+}
+
+static void bench_approx_math() {
+    BENCH_FN_FUNC_FN(approx_recip);
+    BENCH_FN_FUNC_FN(approx_sqrt);
+    BENCH_FN_FUNC_FN(approx_rsqrt);
+    BENCH_FN_FUNC_FN(approx_length);
+    BENCH_FN_FUNC_FN_FN(approx_distance);
+    BENCH_FN_FUNC_FN(approx_normalize);
+    BENCH_FN_FUNC_FN(approx_atan);
+}
+
+void bench() {
+    rsDebug("RS Compute Benchmark", 0);
+    rsDebug("Current configuration:", 0);
+    rsDebug("Priming runs", priming_runs);
+    rsDebug("Timing runs", timing_runs);
+    rsDebug("Beginning test", 0);
+    inv_timing_runs = 1000000.f / (float)timing_runs;
+    bench_basic_operators();
+    bench_convert();
+    bench_int_math();
+    bench_fp_math();
+    bench_approx_math();
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Fisheye.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Fisheye.java
index bf68f91..81868b10 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Fisheye.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Fisheye.java
@@ -26,12 +26,16 @@
 public class Fisheye extends TestBase {
     private ScriptC_fisheye_full mScript_full = null;
     private ScriptC_fisheye_relaxed mScript_relaxed = null;
+    private ScriptC_fisheye_approx_full mScript_approx_full = null;
+    private ScriptC_fisheye_approx_relaxed mScript_approx_relaxed = null;
+    private final boolean approx;
     private final boolean relaxed;
     private float center_x = 0.5f;
     private float center_y = 0.5f;
     private float scale = 0.5f;
 
-    public Fisheye(boolean relaxed) {
+    public Fisheye(boolean approx, boolean relaxed) {
+        this.approx = approx;
         this.relaxed = relaxed;
     }
 
@@ -68,7 +72,18 @@
     }
 
     private void do_init() {
-        if (relaxed)
+        if (approx) {
+            if (relaxed)
+                mScript_approx_relaxed.invoke_init_filter(
+                        mInPixelsAllocation.getType().getX(),
+                        mInPixelsAllocation.getType().getY(), center_x,
+                        center_y, scale);
+            else
+                mScript_approx_full.invoke_init_filter(
+                        mInPixelsAllocation.getType().getX(),
+                        mInPixelsAllocation.getType().getY(), center_x,
+                        center_y, scale);
+        } else if (relaxed)
             mScript_relaxed.invoke_init_filter(
                     mInPixelsAllocation.getType().getX(),
                     mInPixelsAllocation.getType().getY(), center_x, center_y,
@@ -81,7 +96,19 @@
     }
 
     public void createTest(android.content.res.Resources res) {
-        if (relaxed) {
+        if (approx) {
+            if (relaxed) {
+                mScript_approx_relaxed = new ScriptC_fisheye_approx_relaxed(mRS,
+                        res, R.raw.fisheye_approx_relaxed);
+                mScript_approx_relaxed.set_in_alloc(mInPixelsAllocation);
+                mScript_approx_relaxed.set_sampler(Sampler.CLAMP_LINEAR(mRS));
+            } else {
+                mScript_approx_full = new ScriptC_fisheye_approx_full(mRS, res,
+                        R.raw.fisheye_approx_full);
+                mScript_approx_full.set_in_alloc(mInPixelsAllocation);
+                mScript_approx_full.set_sampler(Sampler.CLAMP_LINEAR(mRS));
+            }
+        } else if (relaxed) {
             mScript_relaxed = new ScriptC_fisheye_relaxed(mRS, res,
                     R.raw.fisheye_relaxed);
             mScript_relaxed.set_in_alloc(mInPixelsAllocation);
@@ -96,7 +123,12 @@
     }
 
     public void runTest() {
-        if (relaxed)
+        if (approx) {
+            if (relaxed)
+                mScript_approx_relaxed.forEach_root(mOutPixelsAllocation);
+            else
+                mScript_approx_full.forEach_root(mOutPixelsAllocation);
+        } else if (relaxed)
             mScript_relaxed.forEach_root(mOutPixelsAllocation);
         else
             mScript_full.forEach_root(mOutPixelsAllocation);
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 7cd485e..07626a3 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -144,29 +144,38 @@
             mTest = new Grain();
             break;
         case 7:
-            mTest = new Fisheye(false);
+            mTest = new Fisheye(false, false);
             break;
         case 8:
-            mTest = new Fisheye(true);
+            mTest = new Fisheye(false, true);
             break;
         case 9:
-            mTest = new Vignette(false, false);
+            mTest = new Fisheye(true, false);
             break;
         case 10:
-            mTest = new Vignette(false, true);
+            mTest = new Fisheye(true, true);
             break;
         case 11:
-            mTest = new Vignette(true, false);
+            mTest = new Vignette(false, false);
             break;
         case 12:
-            mTest = new Vignette(true, true);
+            mTest = new Vignette(false, true);
             break;
         case 13:
-            mTest = new GroupTest(true);
+            mTest = new Vignette(true, false);
             break;
         case 14:
+            mTest = new Vignette(true, true);
+            break;
+        case 15:
+            mTest = new GroupTest(true);
+            break;
+        case 16:
             mTest = new GroupTest(false);
             break;
+        case 17:
+            mTest = new Intrinsics(0);
+            break;
         }
 
         mTest.createBaseTest(this, mBitmapIn);
@@ -179,7 +188,7 @@
     }
 
     void setupTests() {
-        mTestNames = new String[15];
+        mTestNames = new String[18];
         mTestNames[0] = "Levels Vec3 Relaxed";
         mTestNames[1] = "Levels Vec4 Relaxed";
         mTestNames[2] = "Levels Vec3 Full";
@@ -189,12 +198,15 @@
         mTestNames[6] = "Grain";
         mTestNames[7] = "Fisheye Full";
         mTestNames[8] = "Fisheye Relaxed";
-        mTestNames[9] = "Vignette Full";
-        mTestNames[10] = "Vignette Relaxed";
-        mTestNames[11] = "Vignette Approximate Full";
-        mTestNames[12] = "Vignette Approximate Relaxed";
-        mTestNames[13] = "Group Test (emulated)";
-        mTestNames[14] = "Group Test (native)";
+        mTestNames[9] = "Fisheye Approximate Full";
+        mTestNames[10] = "Fisheye Approximate Relaxed";
+        mTestNames[11] = "Vignette Full";
+        mTestNames[12] = "Vignette Relaxed";
+        mTestNames[13] = "Vignette Approximate Full";
+        mTestNames[14] = "Vignette Approximate Relaxed";
+        mTestNames[15] = "Group Test (emulated)";
+        mTestNames[16] = "Group Test (native)";
+        mTestNames[17] = "Intrinsics Convolve 3x3";
         mTestSpinner.setAdapter(new ArrayAdapter<String>(
             this, R.layout.spinner_layout, mTestNames));
     }
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Intrinsics.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Intrinsics.java
new file mode 100644
index 0000000..dab8111
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Intrinsics.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.image;
+
+import java.lang.Math;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.RenderScript;
+import android.renderscript.Script;
+import android.renderscript.ScriptIntrinsicConvolve3x3;
+import android.renderscript.Type;
+import android.util.Log;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+public class Intrinsics extends TestBase {
+    private ScriptIntrinsicConvolve3x3 mScript;
+
+    Intrinsics(int id) {
+    }
+
+    public boolean onBar1Setup(SeekBar b, TextView t) {
+        t.setText("Strength");
+        b.setProgress(50);
+        return true;
+    }
+
+    public void onBar1Changed(int progress) {
+        float s = progress / 100.0f;
+        float v[] = new float[9];
+        v[0] = 0.f;     v[1] = -s;      v[2] = 0.f;
+        v[3] = -s;      v[4] = s*4+1;   v[5] = -s;
+        v[6] = 0.f;     v[7] = -s;      v[8] = 0.f;
+        mScript.setColorMatrix(v);
+    }
+
+
+    public void createTest(android.content.res.Resources res) {
+        mScript = ScriptIntrinsicConvolve3x3.create(mRS, Element.RGBA_8888(mRS));
+    }
+
+    public void runTest() {
+        mScript.setInput(mInPixelsAllocation);
+        mScript.forEach(mOutPixelsAllocation);
+    }
+
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye.rsh b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye.rsh
index 4dcfc1d..3809912 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye.rsh
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye.rsh
@@ -17,46 +17,41 @@
 rs_allocation in_alloc;
 rs_sampler sampler;
 
-static float2 center, dimensions;
-static float2 scale;
-static float alpha;
-static float radius2;
-static float factor;
+static float2 center, neg_center, inv_dimensions, axis_scale;
+static float alpha, radius2, factor;
 
-void init_filter(uint32_t dim_x, uint32_t dim_y, float focus_x, float focus_y, float k) {
-    center.x = focus_x;
-    center.y = focus_y;
-    dimensions.x = (float)dim_x;
-    dimensions.y = (float)dim_y;
-
+void init_filter(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y, float k) {
+    center.x = center_x;
+    center.y = center_y;
+    neg_center = -center;
+    inv_dimensions.x = 1.f / (float)dim_x;
+    inv_dimensions.y = 1.f / (float)dim_y;
     alpha = k * 2.0 + 0.75;
-    float bound2 = 0.25;
-    if (dim_x > dim_y) {
-        scale.x = 1.0;
-        scale.y = dimensions.y / dimensions.x;
-        bound2 *= (scale.y*scale.y + 1);
-    } else {
-        scale.x = dimensions.x / dimensions.y;
-        scale.y = 1.0;
-        bound2 *= (scale.x*scale.x + 1);
-    }
+
+    axis_scale = (float2)1.f;
+    if (dim_x > dim_y)
+        axis_scale.y = (float)dim_y / (float)dim_x;
+    else
+        axis_scale.x = (float)dim_x / (float)dim_y;
+    
+    const float bound2 = 0.25 * (axis_scale.x*axis_scale.x + axis_scale.y*axis_scale.y);
     const float bound = sqrt(bound2);
     const float radius = 1.15 * bound;
     radius2 = radius*radius;
-    const float max_radian = 0.5f * M_PI - atan(alpha / bound * sqrt(radius2 - bound2));
+    const float max_radian = M_PI_2 - atan(alpha / bound * sqrt(radius2 - bound2));
     factor = bound / max_radian;
 }
 
 void root(uchar4 *out, uint32_t x, uint32_t y) {
     // Convert x and y to floating point coordinates with center as origin
-    float2 coord;
-    coord.x = (float)x / dimensions.x;
-    coord.y = (float)y / dimensions.y;
-    coord -= center;
-    const float dist = length(scale * coord);
-    const float radian = M_PI_2 - atan((alpha * sqrt(radius2 - dist * dist)) / dist);
-    const float scalar = radian * factor / dist;
-    const float2 new_coord = coord * scalar + center;
+    const float2 inCoord = {(float)x, (float)y};
+    const float2 coord = mad(inCoord, inv_dimensions, neg_center);
+    const float2 scaledCoord = axis_scale * coord;
+    const float dist2 = scaledCoord.x*scaledCoord.x + scaledCoord.y*scaledCoord.y;
+    const float inv_dist = rsqrt(dist2);
+    const float radian = M_PI_2 - atan((alpha * sqrt(radius2 - dist2)) * inv_dist);
+    const float scalar = radian * factor * inv_dist;
+    const float2 new_coord = mad(coord, scalar, center);
     const float4 fout = rsSample(in_alloc, sampler, new_coord);
     *out = rsPackColorTo8888(fout);
 }
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx.rsh b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx.rsh
new file mode 100644
index 0000000..008acbe
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx.rsh
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+rs_allocation in_alloc;
+rs_sampler sampler;
+
+static float2 center, neg_center, inv_dimensions, axis_scale;
+static float alpha, radius2, factor;
+
+void init_filter(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y, float k) {
+    center.x = center_x;
+    center.y = center_y;
+    neg_center = -center;
+    inv_dimensions.x = 1.f / (float)dim_x;
+    inv_dimensions.y = 1.f / (float)dim_y;
+    alpha = k * 2.0 + 0.75;
+
+    axis_scale = (float2)1.f;
+    if (dim_x > dim_y)
+        axis_scale.y = (float)dim_y / (float)dim_x;
+    else
+        axis_scale.x = (float)dim_x / (float)dim_y;
+
+    const float bound2 = 0.25 * (axis_scale.x*axis_scale.x + axis_scale.y*axis_scale.y);
+    const float bound = sqrt(bound2);
+    const float radius = 1.15 * bound;
+    radius2 = radius*radius;
+    const float max_radian = M_PI_2 - atan(alpha / bound * sqrt(radius2 - bound2));
+    factor = bound / max_radian;
+}
+
+void root(uchar4 *out, uint32_t x, uint32_t y) {
+    // Convert x and y to floating point coordinates with center as origin
+    const float2 inCoord = {(float)x, (float)y};
+    const float2 coord = mad(inCoord, inv_dimensions, neg_center);
+    const float2 scaledCoord = axis_scale * coord;
+    const float dist2 = scaledCoord.x*scaledCoord.x + scaledCoord.y*scaledCoord.y;
+    const float inv_dist = approx_rsqrt(dist2);
+    const float radian = M_PI_2 - approx_atan((alpha * approx_sqrt(radius2 - dist2)) * inv_dist);
+    const float scalar = radian * factor * inv_dist;
+    const float2 new_coord = mad(coord, scalar, center);
+    const float4 fout = rsSample(in_alloc, sampler, new_coord);
+    *out = rsPackColorTo8888(fout);
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx_full.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx_full.rs
new file mode 100644
index 0000000..1ea37db
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx_full.rs
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+
+#include "fisheye_approx.rsh"
+
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx_relaxed.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx_relaxed.rs
new file mode 100644
index 0000000..3e76368
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/fisheye_approx_relaxed.rs
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image)
+#pragma rs_fp_relaxed
+
+#include "fisheye_approx.rsh"
+
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.rs
index 97ae4fb..7d9d3ac 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.rs
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.rs
@@ -43,10 +43,10 @@
 
 rs_allocation gBlendSource;
 void blend9(uchar *out, uint32_t x, uint32_t y) {
-    uint32_t x1 = min(x+1, (uint32_t)gWidth);
-    uint32_t x2 = max(x-1, (uint32_t)0);
-    uint32_t y1 = min(y+1, (uint32_t)gHeight);
-    uint32_t y2 = max(y-1, (uint32_t)0);
+    uint32_t x1 = min((int32_t)x+1, (int32_t)gWidth);
+    uint32_t x2 = max((int32_t)x-1, (int32_t)0);
+    uint32_t y1 = min((int32_t)y+1, (int32_t)gHeight);
+    uint32_t y2 = max((int32_t)y-1, (int32_t)0);
 
     uint p00 = 56 *  ((uchar *)rsGetElementAt(gBlendSource, x1, y1))[0];
     uint p01 = 114 * ((uchar *)rsGetElementAt(gBlendSource, x, y1))[0];
diff --git a/tests/RenderScriptTests/ImageProcessing2/Android.mk b/tests/RenderScriptTests/ImageProcessing2/Android.mk
new file mode 100644
index 0000000..e05a518
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/Android.mk
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+                   $(call all-renderscript-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := android.support.v8.renderscript
+
+LOCAL_PACKAGE_NAME := ImageProcessing2
+LOCAL_SDK_VERSION := 8
+LOCAL_RENDERSCRIPT_TARGET_API := 17
+LOCAL_RENDERSCRIPT_INCLUDES_OVERRIDE := $(TOPDIR)external/clang/lib/Headers \
+                                        $(TOPDIR)frameworks/rs/scriptc
+
+LOCAL_RENDERSCRIPT_FLAGS := -rs-package-name=android.support.v8.renderscript
+LOCAL_REQUIRED_MODULES := librsjni
+
+include $(BUILD_PACKAGE)
+
+#include $(call all-makefiles-under, $(LOCAL_PATH))
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/AndroidManifest.xml b/tests/RenderScriptTests/ImageProcessing2/AndroidManifest.xml
new file mode 100644
index 0000000..20ee053
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/AndroidManifest.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.rs.image2">
+    <uses-sdk android:minSdkVersion="8" />
+    <application android:label="IP GB">
+        <activity android:name="ImageProcessingActivity2">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/city.png b/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/city.png
new file mode 100644
index 0000000..856eeff
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/res/drawable-nodpi/city.png
Binary files differ
diff --git a/tests/RenderScriptTests/ImageProcessing2/res/layout/main.xml b/tests/RenderScriptTests/ImageProcessing2/res/layout/main.xml
new file mode 100644
index 0000000..bd56d62
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/res/layout/main.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+            android:orientation="vertical"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent"
+            android:id="@+id/toplevel">
+    <SurfaceView
+        android:id="@+id/surface"
+        android:layout_width="1dip"
+        android:layout_height="1dip" />
+    <ScrollView
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:orientation="vertical"
+                android:layout_width="fill_parent"
+                android:layout_height="fill_parent">
+            <ImageView
+                android:id="@+id/display"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
+            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:orientation="horizontal"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content">
+                    <Button
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/benchmark"
+                        android:onClick="benchmark"/>
+                    <TextView
+                        android:id="@+id/benchmarkText"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:textSize="8pt"
+                        android:text="@string/saturation"/>
+            </LinearLayout>
+            <Spinner
+                android:id="@+id/filterselection"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"/>
+            <TextView
+                android:id="@+id/slider1Text"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textSize="8pt"
+                android:layout_marginLeft="10sp"
+                android:layout_marginTop="15sp"
+                android:text="@string/saturation"/>
+             <SeekBar
+                android:id="@+id/slider1"
+                android:layout_marginLeft="10sp"
+                android:layout_marginRight="10sp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+            <TextView
+                android:id="@+id/slider2Text"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textSize="8pt"
+                android:layout_marginLeft="10sp"
+                android:layout_marginTop="15sp"
+                android:text="@string/gamma"/>
+            <SeekBar
+                android:id="@+id/slider2"
+                android:layout_marginLeft="10sp"
+                android:layout_marginRight="10sp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+            <TextView
+                android:id="@+id/slider3Text"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="10sp"
+                android:layout_marginTop="15sp"
+                android:textSize="8pt"
+                android:text="@string/out_white"/>
+            <SeekBar
+                android:id="@+id/slider3"
+                android:layout_marginLeft="10sp"
+                android:layout_marginRight="10sp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+            <TextView
+                android:id="@+id/slider4Text"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textSize="8pt"
+                android:layout_marginLeft="10sp"
+                android:layout_marginTop="15sp"
+                android:text="@string/in_white"/>
+            <SeekBar
+                android:id="@+id/slider4"
+                android:layout_marginLeft="10sp"
+                android:layout_marginRight="10sp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+            <TextView
+                android:id="@+id/slider5Text"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textSize="8pt"
+                android:layout_marginLeft="10sp"
+                android:layout_marginTop="15sp"
+                android:text="@string/in_white"/>
+            <SeekBar
+                android:id="@+id/slider5"
+                android:layout_marginLeft="10sp"
+                android:layout_marginRight="10sp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+            </LinearLayout>
+    </ScrollView>
+</LinearLayout>
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/res/layout/spinner_layout.xml b/tests/RenderScriptTests/ImageProcessing2/res/layout/spinner_layout.xml
new file mode 100644
index 0000000..8196bbf
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/res/layout/spinner_layout.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:padding="10dp"
+    android:textSize="16sp"
+/>
diff --git a/tests/RenderScriptTests/ImageProcessing2/res/values/strings.xml b/tests/RenderScriptTests/ImageProcessing2/res/values/strings.xml
new file mode 100644
index 0000000..cc5cc4d
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/res/values/strings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2008 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- General -->
+    <skip />
+    <!--slider label -->
+    <string name="blur_description">Blur Radius</string>
+    <string name="in_white">In White</string>
+    <string name="out_white">Out White</string>
+    <string name="in_black">In Black</string>
+    <string name="out_black">Out Black</string>
+    <string name="gamma">Gamma</string>
+    <string name="saturation">Saturation</string>
+    <string name="benchmark">Benchmark</string>
+
+</resources>
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blur25.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blur25.java
new file mode 100644
index 0000000..be87716
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Blur25.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.image2;
+
+import java.lang.Math;
+
+import android.support.v8.renderscript.*;
+import android.util.Log;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+public class Blur25 extends TestBase {
+    private int MAX_RADIUS = 25;
+    private ScriptC_threshold mScript;
+    private ScriptC_vertical_blur mScriptVBlur;
+    private ScriptC_horizontal_blur mScriptHBlur;
+    private int mRadius = MAX_RADIUS;
+    private float mSaturation = 1.0f;
+    private Allocation mScratchPixelsAllocation1;
+    private Allocation mScratchPixelsAllocation2;
+
+
+    public boolean onBar1Setup(SeekBar b, TextView t) {
+        t.setText("Radius");
+        b.setProgress(100);
+        return true;
+    }
+    public boolean onBar2Setup(SeekBar b, TextView t) {
+        b.setProgress(50);
+        t.setText("Saturation");
+        return true;
+    }
+
+
+    public void onBar1Changed(int progress) {
+        float fRadius = progress / 100.0f;
+        fRadius *= (float)(MAX_RADIUS);
+        mRadius = (int)fRadius;
+        mScript.set_radius(mRadius);
+    }
+    public void onBar2Changed(int progress) {
+        mSaturation = (float)progress / 50.0f;
+        mScriptVBlur.invoke_setSaturation(mSaturation);
+    }
+
+
+    public void createTest(android.content.res.Resources res) {
+        int width = mInPixelsAllocation.getType().getX();
+        int height = mInPixelsAllocation.getType().getY();
+
+        Type.Builder tb = new Type.Builder(mRS, Element.F32_4(mRS));
+        tb.setX(width);
+        tb.setY(height);
+        mScratchPixelsAllocation1 = Allocation.createTyped(mRS, tb.create());
+        mScratchPixelsAllocation2 = Allocation.createTyped(mRS, tb.create());
+
+        mScriptVBlur = new ScriptC_vertical_blur(mRS, res, R.raw.vertical_blur);
+        mScriptHBlur = new ScriptC_horizontal_blur(mRS, res, R.raw.horizontal_blur);
+
+        mScript = new ScriptC_threshold(mRS, res, R.raw.threshold);
+        mScript.set_width(width);
+        mScript.set_height(height);
+        mScript.set_radius(mRadius);
+
+        mScriptVBlur.invoke_setSaturation(mSaturation);
+
+        mScript.bind_InPixel(mInPixelsAllocation);
+        mScript.bind_OutPixel(mOutPixelsAllocation);
+        mScript.bind_ScratchPixel1(mScratchPixelsAllocation1);
+        mScript.bind_ScratchPixel2(mScratchPixelsAllocation2);
+
+        mScript.set_vBlurScript(mScriptVBlur);
+        mScript.set_hBlurScript(mScriptHBlur);
+    }
+
+    public void runTest() {
+        mScript.invoke_filter();
+    }
+
+    public void setupBenchmark() {
+        mScript.set_radius(MAX_RADIUS);
+    }
+
+    public void exitBenchmark() {
+        mScript.set_radius(mRadius);
+    }
+}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Fisheye.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Fisheye.java
new file mode 100644
index 0000000..995cf9d
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Fisheye.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.image2;
+
+import android.support.v8.renderscript.*;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+public class Fisheye extends TestBase {
+    private ScriptC_fisheye_full mScript_full = null;
+    private ScriptC_fisheye_relaxed mScript_relaxed = null;
+    private final boolean relaxed;
+    private float center_x = 0.5f;
+    private float center_y = 0.5f;
+    private float scale = 0.5f;
+
+    public Fisheye(boolean relaxed) {
+        this.relaxed = relaxed;
+    }
+
+    public boolean onBar1Setup(SeekBar b, TextView t) {
+        t.setText("Scale");
+        b.setMax(100);
+        b.setProgress(25);
+        return true;
+    }
+    public boolean onBar2Setup(SeekBar b, TextView t) {
+        t.setText("Shift center X");
+        b.setMax(100);
+        b.setProgress(50);
+        return true;
+    }
+    public boolean onBar3Setup(SeekBar b, TextView t) {
+        t.setText("Shift center Y");
+        b.setMax(100);
+        b.setProgress(50);
+        return true;
+    }
+
+    public void onBar1Changed(int progress) {
+        scale = progress / 50.0f;
+        do_init();
+    }
+    public void onBar2Changed(int progress) {
+        center_x = progress / 100.0f;
+        do_init();
+    }
+    public void onBar3Changed(int progress) {
+        center_y = progress / 100.0f;
+        do_init();
+    }
+
+    private void do_init() {
+        if (relaxed)
+            mScript_relaxed.invoke_init_filter(
+                    mInPixelsAllocation.getType().getX(),
+                    mInPixelsAllocation.getType().getY(), center_x, center_y,
+                    scale);
+        else
+            mScript_full.invoke_init_filter(
+                    mInPixelsAllocation.getType().getX(),
+                    mInPixelsAllocation.getType().getY(), center_x, center_y,
+                    scale);
+    }
+
+    public void createTest(android.content.res.Resources res) {
+        if (relaxed) {
+            mScript_relaxed = new ScriptC_fisheye_relaxed(mRS, res,
+                    R.raw.fisheye_relaxed);
+            mScript_relaxed.set_in_alloc(mInPixelsAllocation);
+            mScript_relaxed.set_sampler(Sampler.CLAMP_LINEAR(mRS));
+        } else {
+            mScript_full = new ScriptC_fisheye_full(mRS, res,
+                    R.raw.fisheye_full);
+            mScript_full.set_in_alloc(mInPixelsAllocation);
+            mScript_full.set_sampler(Sampler.CLAMP_LINEAR(mRS));
+        }
+        do_init();
+    }
+
+    public void runTest() {
+        if (relaxed)
+            mScript_relaxed.forEach_root(mOutPixelsAllocation);
+        else
+            mScript_full.forEach_root(mOutPixelsAllocation);
+    }
+
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Grain.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Grain.java
new file mode 100644
index 0000000..e00edd7
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Grain.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.image2;
+
+import java.lang.Math;
+
+import android.support.v8.renderscript.*;
+import android.util.Log;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+public class Grain extends TestBase {
+    private ScriptC_grain mScript;
+    private Allocation mNoise;
+    private Allocation mNoise2;
+
+
+    public boolean onBar1Setup(SeekBar b, TextView t) {
+        t.setText("Strength");
+        b.setProgress(50);
+        return true;
+    }
+
+    public void onBar1Changed(int progress) {
+        float s = progress / 100.0f;
+        mScript.set_gNoiseStrength(s);
+    }
+
+    public void createTest(android.content.res.Resources res) {
+        int width = mInPixelsAllocation.getType().getX();
+        int height = mInPixelsAllocation.getType().getY();
+
+        Type.Builder tb = new Type.Builder(mRS, Element.U8(mRS));
+        tb.setX(width);
+        tb.setY(height);
+        mNoise = Allocation.createTyped(mRS, tb.create());
+        mNoise2 = Allocation.createTyped(mRS, tb.create());
+
+        mScript = new ScriptC_grain(mRS, res, R.raw.grain);
+        mScript.set_gWidth(width);
+        mScript.set_gHeight(height);
+        mScript.set_gNoiseStrength(0.5f);
+        mScript.set_gBlendSource(mNoise);
+        mScript.set_gNoise(mNoise2);
+    }
+
+    public void runTest() {
+        mScript.forEach_genRand(mNoise);
+        mScript.forEach_blend9(mNoise2);
+        mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
+    }
+
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Greyscale.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Greyscale.java
new file mode 100644
index 0000000..2d85ae7
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Greyscale.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.image2;
+
+import java.lang.Math;
+
+import android.support.v8.renderscript.*;
+import android.util.Log;
+
+public class Greyscale extends TestBase {
+    private ScriptC_greyscale mScript;
+
+    public void createTest(android.content.res.Resources res) {
+        mScript = new ScriptC_greyscale(mRS, res, R.raw.greyscale);
+    }
+
+    public void runTest() {
+        mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
+    }
+
+}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/GroupTest.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/GroupTest.java
new file mode 100644
index 0000000..b9fbb59
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/GroupTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.image2;
+
+import java.lang.Math;
+
+import android.support.v8.renderscript.*;
+import android.util.Log;
+
+public class GroupTest extends TestBase {
+    private ScriptC_convolve3x3 mConvolve;
+    private ScriptC_colormatrix mMatrix;
+
+    private Allocation mScratchPixelsAllocation1;
+    private ScriptGroup mGroup;
+
+    private int mWidth;
+    private int mHeight;
+    private boolean mUseNative;
+
+
+    public GroupTest(boolean useNative) {
+        mUseNative = useNative;
+    }
+
+    public void createTest(android.content.res.Resources res) {
+        mWidth = mInPixelsAllocation.getType().getX();
+        mHeight = mInPixelsAllocation.getType().getY();
+
+        mConvolve = new ScriptC_convolve3x3(mRS, res, R.raw.convolve3x3);
+        mMatrix = new ScriptC_colormatrix(mRS, res, R.raw.colormatrix);
+
+        float f[] = new float[9];
+        f[0] =  0.f;    f[1] = -1.f;    f[2] =  0.f;
+        f[3] = -1.f;    f[4] =  5.f;    f[5] = -1.f;
+        f[6] =  0.f;    f[7] = -1.f;    f[8] =  0.f;
+        mConvolve.set_gCoeffs(f);
+
+        Matrix4f m = new Matrix4f();
+        m.set(1, 0, 0.2f);
+        m.set(1, 1, 0.9f);
+        m.set(1, 2, 0.2f);
+        mMatrix.invoke_setMatrix(m);
+
+        Type.Builder tb = new Type.Builder(mRS, Element.U8_4(mRS));
+        tb.setX(mWidth);
+        tb.setY(mHeight);
+        Type connect = tb.create();
+
+        if (mUseNative) {
+            ScriptGroup.Builder b = new ScriptGroup.Builder(mRS);
+            b.addConnection(connect, mConvolve, mMatrix, null);
+            mGroup = b.create();
+
+        } else {
+            mScratchPixelsAllocation1 = Allocation.createTyped(mRS, connect);
+        }
+    }
+
+    public void runTest() {
+        mConvolve.set_gIn(mInPixelsAllocation);
+        mConvolve.set_gWidth(mWidth);
+        mConvolve.set_gHeight(mHeight);
+        if (mUseNative) {
+            mGroup.setOutput(mMatrix, mOutPixelsAllocation);
+            mGroup.execute();
+        } else {
+            mConvolve.forEach_root(mScratchPixelsAllocation1);
+            mMatrix.forEach_root(mScratchPixelsAllocation1, mOutPixelsAllocation);
+        }
+    }
+
+}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ImageProcessingActivity2.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ImageProcessingActivity2.java
new file mode 100644
index 0000000..9b36da14
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ImageProcessingActivity2.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.image2;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.support.v8.renderscript.*;
+import android.view.SurfaceView;
+import android.view.SurfaceHolder;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.view.View;
+import android.util.Log;
+import java.lang.Math;
+
+public class ImageProcessingActivity2 extends Activity
+                                       implements SeekBar.OnSeekBarChangeListener {
+    private final String TAG = "Img";
+    Bitmap mBitmapIn;
+    Bitmap mBitmapOut;
+    String mTestNames[];
+
+    private SeekBar mBar1;
+    private SeekBar mBar2;
+    private SeekBar mBar3;
+    private SeekBar mBar4;
+    private SeekBar mBar5;
+    private TextView mText1;
+    private TextView mText2;
+    private TextView mText3;
+    private TextView mText4;
+    private TextView mText5;
+
+    private float mSaturation = 1.0f;
+
+    private TextView mBenchmarkResult;
+    private Spinner mTestSpinner;
+
+    private SurfaceView mSurfaceView;
+    private ImageView mDisplayView;
+
+    private boolean mDoingBenchmark;
+
+    private TestBase mTest;
+
+
+    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+        if (fromUser) {
+
+            if (seekBar == mBar1) {
+                mTest.onBar1Changed(progress);
+            } else if (seekBar == mBar2) {
+                mTest.onBar2Changed(progress);
+            } else if (seekBar == mBar3) {
+                mTest.onBar3Changed(progress);
+            } else if (seekBar == mBar4) {
+                mTest.onBar4Changed(progress);
+            } else if (seekBar == mBar5) {
+                mTest.onBar5Changed(progress);
+            }
+
+            mTest.runTest();
+            mTest.updateBitmap(mBitmapOut);
+            mDisplayView.invalidate();
+        }
+    }
+
+    public void onStartTrackingTouch(SeekBar seekBar) {
+    }
+
+    public void onStopTrackingTouch(SeekBar seekBar) {
+    }
+
+    void setupBars() {
+        mBar1.setVisibility(View.VISIBLE);
+        mText1.setVisibility(View.VISIBLE);
+        mTest.onBar1Setup(mBar1, mText1);
+
+        mBar2.setVisibility(View.VISIBLE);
+        mText2.setVisibility(View.VISIBLE);
+        mTest.onBar2Setup(mBar2, mText2);
+
+        mBar3.setVisibility(View.VISIBLE);
+        mText3.setVisibility(View.VISIBLE);
+        mTest.onBar3Setup(mBar3, mText3);
+
+        mBar4.setVisibility(View.VISIBLE);
+        mText4.setVisibility(View.VISIBLE);
+        mTest.onBar4Setup(mBar4, mText4);
+
+        mBar5.setVisibility(View.VISIBLE);
+        mText5.setVisibility(View.VISIBLE);
+        mTest.onBar5Setup(mBar5, mText5);
+    }
+
+
+    void changeTest(int testID) {
+        switch(testID) {
+        case 0:
+            mTest = new LevelsV4(false, false);
+            break;
+        case 1:
+            mTest = new LevelsV4(false, true);
+            break;
+        case 2:
+            mTest = new LevelsV4(true, false);
+            break;
+        case 3:
+            mTest = new LevelsV4(true, true);
+            break;
+        case 4:
+            mTest = new Blur25();
+            break;
+        case 5:
+            mTest = new Greyscale();
+            break;
+        case 6:
+            mTest = new Grain();
+            break;
+        case 7:
+            mTest = new Fisheye(false);
+            break;
+        case 8:
+            mTest = new Fisheye(true);
+            break;
+        case 9:
+            mTest = new Vignette(false);
+            break;
+        case 10:
+            mTest = new Vignette(true);
+            break;
+        case 11:
+            mTest = new GroupTest(false);
+            break;
+        case 12:
+            mTest = new GroupTest(true);
+            break;
+        }
+
+        mTest.createBaseTest(this, mBitmapIn);
+        setupBars();
+
+        mTest.runTest();
+        mTest.updateBitmap(mBitmapOut);
+        mDisplayView.invalidate();
+        mBenchmarkResult.setText("Result: not run");
+    }
+
+    void setupTests() {
+        mTestNames = new String[13];
+        mTestNames[0] = "Levels Vec3 Relaxed";
+        mTestNames[1] = "Levels Vec4 Relaxed";
+        mTestNames[2] = "Levels Vec3 Full";
+        mTestNames[3] = "Levels Vec4 Full";
+        mTestNames[4] = "Blur radius 25";
+        mTestNames[5] = "Greyscale";
+        mTestNames[6] = "Grain";
+        mTestNames[7] = "Fisheye Full";
+        mTestNames[8] = "Fisheye Relaxed";
+        mTestNames[9] = "Vignette Full";
+        mTestNames[10] = "Vignette Relaxed";
+        mTestNames[11] = "Group Test (emulated)";
+        mTestNames[12] = "Group Test (native)";
+        mTestSpinner.setAdapter(new ArrayAdapter<String>(
+            this, R.layout.spinner_layout, mTestNames));
+    }
+
+    private AdapterView.OnItemSelectedListener mTestSpinnerListener =
+            new AdapterView.OnItemSelectedListener() {
+                public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
+                    changeTest(pos);
+                }
+
+                public void onNothingSelected(AdapterView parent) {
+
+                }
+            };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+
+        mBitmapIn = loadBitmap(R.drawable.city);
+        mBitmapOut = loadBitmap(R.drawable.city);
+
+        mSurfaceView = (SurfaceView) findViewById(R.id.surface);
+
+        mDisplayView = (ImageView) findViewById(R.id.display);
+        mDisplayView.setImageBitmap(mBitmapOut);
+
+        mBar1 = (SeekBar) findViewById(R.id.slider1);
+        mBar2 = (SeekBar) findViewById(R.id.slider2);
+        mBar3 = (SeekBar) findViewById(R.id.slider3);
+        mBar4 = (SeekBar) findViewById(R.id.slider4);
+        mBar5 = (SeekBar) findViewById(R.id.slider5);
+
+        mBar1.setOnSeekBarChangeListener(this);
+        mBar2.setOnSeekBarChangeListener(this);
+        mBar3.setOnSeekBarChangeListener(this);
+        mBar4.setOnSeekBarChangeListener(this);
+        mBar5.setOnSeekBarChangeListener(this);
+
+        mText1 = (TextView) findViewById(R.id.slider1Text);
+        mText2 = (TextView) findViewById(R.id.slider2Text);
+        mText3 = (TextView) findViewById(R.id.slider3Text);
+        mText4 = (TextView) findViewById(R.id.slider4Text);
+        mText5 = (TextView) findViewById(R.id.slider5Text);
+
+        mTestSpinner = (Spinner) findViewById(R.id.filterselection);
+        mTestSpinner.setOnItemSelectedListener(mTestSpinnerListener);
+
+        mBenchmarkResult = (TextView) findViewById(R.id.benchmarkText);
+        mBenchmarkResult.setText("Result: not run");
+
+        setupTests();
+        changeTest(0);
+    }
+
+
+    private Bitmap loadBitmap(int resource) {
+        final BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+        return copyBitmap(BitmapFactory.decodeResource(getResources(), resource, options));
+    }
+
+    private static Bitmap copyBitmap(Bitmap source) {
+        Bitmap b = Bitmap.createBitmap(source.getWidth(), source.getHeight(), source.getConfig());
+        Canvas c = new Canvas(b);
+        c.drawBitmap(source, 0, 0, null);
+        source.recycle();
+        return b;
+    }
+
+    // button hook
+    public void benchmark(View v) {
+        long t = getBenchmark();
+        //long javaTime = javaFilter();
+        //mBenchmarkResult.setText("RS: " + t + " ms  Java: " + javaTime + " ms");
+        mBenchmarkResult.setText("Result: " + t + " ms");
+    }
+
+    // For benchmark test
+    public long getBenchmark() {
+        mDoingBenchmark = true;
+
+        mTest.setupBenchmark();
+        long result = 0;
+
+        Log.v(TAG, "Warming");
+        long t = java.lang.System.currentTimeMillis() + 2000;
+        do {
+            mTest.runTest();
+            mTest.finish();
+        } while (t > java.lang.System.currentTimeMillis());
+
+
+        Log.v(TAG, "Benchmarking");
+        t = java.lang.System.currentTimeMillis();
+        mTest.runTest();
+        mTest.finish();
+        t = java.lang.System.currentTimeMillis() - t;
+
+        Log.v(TAG, "getBenchmark: Renderscript frame time core ms " + t);
+        mTest.exitBenchmark();
+        mDoingBenchmark = false;
+
+        return t;
+    }
+}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/LevelsV4.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/LevelsV4.java
new file mode 100644
index 0000000..fbe3727
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/LevelsV4.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.image2;
+
+import java.lang.Math;
+
+import android.support.v8.renderscript.*;
+import android.util.Log;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+
+public class LevelsV4 extends TestBase {
+    private ScriptC_levels_relaxed mScriptR;
+    private ScriptC_levels_full mScriptF;
+    private float mInBlack = 0.0f;
+    private float mOutBlack = 0.0f;
+    private float mInWhite = 255.0f;
+    private float mOutWhite = 255.0f;
+    private float mSaturation = 1.0f;
+
+    Matrix3f satMatrix = new Matrix3f();
+    float mInWMinInB;
+    float mOutWMinOutB;
+    float mOverInWMinInB;
+
+    boolean mUseFull;
+    boolean mUseV4;
+
+    LevelsV4(boolean useFull, boolean useV4) {
+        mUseFull = useFull;
+        mUseV4 = useV4;
+    }
+
+
+    private void setLevels() {
+        mInWMinInB = mInWhite - mInBlack;
+        mOutWMinOutB = mOutWhite - mOutBlack;
+        mOverInWMinInB = 1.f / mInWMinInB;
+
+        mScriptR.set_inBlack(mInBlack);
+        mScriptR.set_outBlack(mOutBlack);
+        mScriptR.set_inWMinInB(mInWMinInB);
+        mScriptR.set_outWMinOutB(mOutWMinOutB);
+        mScriptR.set_overInWMinInB(mOverInWMinInB);
+        mScriptF.set_inBlack(mInBlack);
+        mScriptF.set_outBlack(mOutBlack);
+        mScriptF.set_inWMinInB(mInWMinInB);
+        mScriptF.set_outWMinOutB(mOutWMinOutB);
+        mScriptF.set_overInWMinInB(mOverInWMinInB);
+    }
+
+    private void setSaturation() {
+        float rWeight = 0.299f;
+        float gWeight = 0.587f;
+        float bWeight = 0.114f;
+        float oneMinusS = 1.0f - mSaturation;
+
+        satMatrix.set(0, 0, oneMinusS * rWeight + mSaturation);
+        satMatrix.set(0, 1, oneMinusS * rWeight);
+        satMatrix.set(0, 2, oneMinusS * rWeight);
+        satMatrix.set(1, 0, oneMinusS * gWeight);
+        satMatrix.set(1, 1, oneMinusS * gWeight + mSaturation);
+        satMatrix.set(1, 2, oneMinusS * gWeight);
+        satMatrix.set(2, 0, oneMinusS * bWeight);
+        satMatrix.set(2, 1, oneMinusS * bWeight);
+        satMatrix.set(2, 2, oneMinusS * bWeight + mSaturation);
+        mScriptR.set_colorMat(satMatrix);
+        mScriptF.set_colorMat(satMatrix);
+    }
+
+    public boolean onBar1Setup(SeekBar b, TextView t) {
+        b.setProgress(50);
+        t.setText("Saturation");
+        return true;
+    }
+    public boolean onBar2Setup(SeekBar b, TextView t) {
+        b.setMax(128);
+        b.setProgress(0);
+        t.setText("In Black");
+        return true;
+    }
+    public boolean onBar3Setup(SeekBar b, TextView t) {
+        b.setMax(128);
+        b.setProgress(0);
+        t.setText("Out Black");
+        return true;
+    }
+    public boolean onBar4Setup(SeekBar b, TextView t) {
+        b.setMax(128);
+        b.setProgress(128);
+        t.setText("Out White");
+        return true;
+    }
+    public boolean onBar5Setup(SeekBar b, TextView t) {
+        b.setMax(128);
+        b.setProgress(128);
+        t.setText("Out White");
+        return true;
+    }
+
+    public void onBar1Changed(int progress) {
+        mSaturation = (float)progress / 50.0f;
+        setSaturation();
+    }
+    public void onBar2Changed(int progress) {
+        mInBlack = (float)progress;
+        setLevels();
+    }
+    public void onBar3Changed(int progress) {
+        mOutBlack = (float)progress;
+        setLevels();
+    }
+    public void onBar4Changed(int progress) {
+        mInWhite = (float)progress + 127.0f;
+        setLevels();
+    }
+    public void onBar5Changed(int progress) {
+        mOutWhite = (float)progress + 127.0f;
+        setLevels();
+    }
+
+    public void createTest(android.content.res.Resources res) {
+        mScriptR = new ScriptC_levels_relaxed(mRS, res, R.raw.levels_relaxed);
+        mScriptF = new ScriptC_levels_full(mRS, res, R.raw.levels_full);
+        setSaturation();
+        setLevels();
+    }
+
+    public void runTest() {
+        if (mUseFull) {
+            if (mUseV4) {
+                mScriptF.forEach_root4(mInPixelsAllocation, mOutPixelsAllocation);
+            } else {
+                mScriptF.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
+            }
+        } else {
+            if (mUseV4) {
+                mScriptR.forEach_root4(mInPixelsAllocation, mOutPixelsAllocation);
+            } else {
+                mScriptR.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
+            }
+        }
+    }
+
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/TestBase.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/TestBase.java
new file mode 100644
index 0000000..35170af
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/TestBase.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.image2;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.support.v8.renderscript.*;
+import android.view.SurfaceView;
+import android.view.SurfaceHolder;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import android.view.View;
+import android.util.Log;
+import java.lang.Math;
+
+public class TestBase  {
+    protected final String TAG = "Img";
+
+    protected RenderScript mRS;
+    protected Allocation mInPixelsAllocation;
+    protected Allocation mOutPixelsAllocation;
+
+    // Override to use UI elements
+    public void onBar1Changed(int progress) {
+    }
+    public void onBar2Changed(int progress) {
+    }
+    public void onBar3Changed(int progress) {
+    }
+    public void onBar4Changed(int progress) {
+    }
+    public void onBar5Changed(int progress) {
+    }
+
+    // Override to use UI elements
+    // Unused bars will be hidden.
+    public boolean onBar1Setup(SeekBar b, TextView t) {
+        b.setVisibility(View.INVISIBLE);
+        t.setVisibility(View.INVISIBLE);
+        return false;
+    }
+    public boolean onBar2Setup(SeekBar b, TextView t) {
+        b.setVisibility(View.INVISIBLE);
+        t.setVisibility(View.INVISIBLE);
+        return false;
+    }
+    public boolean onBar3Setup(SeekBar b, TextView t) {
+        b.setVisibility(View.INVISIBLE);
+        t.setVisibility(View.INVISIBLE);
+        return false;
+    }
+    public boolean onBar4Setup(SeekBar b, TextView t) {
+        b.setVisibility(View.INVISIBLE);
+        t.setVisibility(View.INVISIBLE);
+        return false;
+    }
+    public boolean onBar5Setup(SeekBar b, TextView t) {
+        b.setVisibility(View.INVISIBLE);
+        t.setVisibility(View.INVISIBLE);
+        return false;
+    }
+
+    public final void createBaseTest(ImageProcessingActivity2 act, Bitmap b) {
+        mRS = RenderScript.create(act);
+        mInPixelsAllocation = Allocation.createFromBitmap(mRS, b,
+                                                          Allocation.MipmapControl.MIPMAP_NONE,
+                                                          Allocation.USAGE_SCRIPT);
+        mOutPixelsAllocation = Allocation.createFromBitmap(mRS, b,
+                                                           Allocation.MipmapControl.MIPMAP_NONE,
+                                                           Allocation.USAGE_SCRIPT);
+        createTest(act.getResources());
+    }
+
+    // Must override
+    public void createTest(android.content.res.Resources res) {
+        android.util.Log.e("img", "implement createTest");
+    }
+
+    // Must override
+    public void runTest() {
+    }
+
+    public void finish() {
+        mRS.finish();
+    }
+
+    public void updateBitmap(Bitmap b) {
+        mOutPixelsAllocation.copyTo(b);
+    }
+
+    // Override to configure specific benchmark config.
+    public void setupBenchmark() {
+    }
+
+    // Override to reset after benchmark.
+    public void exitBenchmark() {
+    }
+}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Vignette.java b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Vignette.java
new file mode 100644
index 0000000..fc69eba
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/Vignette.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.image2;
+
+import android.support.v8.renderscript.*;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+public class Vignette extends TestBase {
+    private ScriptC_vignette_full mScript_full = null;
+    private ScriptC_vignette_relaxed mScript_relaxed = null;
+    private final boolean relaxed;
+    private float center_x = 0.5f;
+    private float center_y = 0.5f;
+    private float scale = 0.5f;
+    private float shade = 0.5f;
+    private float slope = 20.0f;
+
+    public Vignette(boolean relaxed) {
+        this.relaxed = relaxed;
+    }
+
+    public boolean onBar1Setup(SeekBar b, TextView t) {
+        t.setText("Scale");
+        b.setMax(100);
+        b.setProgress(25);
+        return true;
+    }
+    public boolean onBar2Setup(SeekBar b, TextView t) {
+        t.setText("Shade");
+        b.setMax(100);
+        b.setProgress(50);
+        return true;
+    }
+    public boolean onBar3Setup(SeekBar b, TextView t) {
+        t.setText("Slope");
+        b.setMax(100);
+        b.setProgress(20);
+        return true;
+    }
+    public boolean onBar4Setup(SeekBar b, TextView t) {
+        t.setText("Shift center X");
+        b.setMax(100);
+        b.setProgress(50);
+        return true;
+    }
+    public boolean onBar5Setup(SeekBar b, TextView t) {
+        t.setText("Shift center Y");
+        b.setMax(100);
+        b.setProgress(50);
+        return true;
+    }
+
+    public void onBar1Changed(int progress) {
+        scale = progress / 50.0f;
+        do_init();
+    }
+    public void onBar2Changed(int progress) {
+        shade = progress / 100.0f;
+        do_init();
+    }
+    public void onBar3Changed(int progress) {
+        slope = (float)progress;
+        do_init();
+    }
+    public void onBar4Changed(int progress) {
+        center_x = progress / 100.0f;
+        do_init();
+    }
+    public void onBar5Changed(int progress) {
+        center_y = progress / 100.0f;
+        do_init();
+    }
+
+    private void do_init() {
+        if (relaxed)
+            mScript_relaxed.invoke_init_vignette(
+                    mInPixelsAllocation.getType().getX(),
+                    mInPixelsAllocation.getType().getY(), center_x, center_y,
+                    scale, shade, slope);
+        else
+            mScript_full.invoke_init_vignette(
+                    mInPixelsAllocation.getType().getX(),
+                    mInPixelsAllocation.getType().getY(), center_x, center_y,
+                    scale, shade, slope);
+    }
+
+    public void createTest(android.content.res.Resources res) {
+        if (relaxed) {
+            mScript_relaxed = new ScriptC_vignette_relaxed(mRS, res,
+                    R.raw.vignette_relaxed);
+        } else {
+            mScript_full = new ScriptC_vignette_full(mRS, res,
+                    R.raw.vignette_full);
+        }
+        do_init();
+    }
+
+    public void runTest() {
+        if (relaxed)
+            mScript_relaxed.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
+        else
+            mScript_full.forEach_root(mInPixelsAllocation, mOutPixelsAllocation);
+    }
+
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/colormatrix.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/colormatrix.rs
new file mode 100644
index 0000000..e93bef3
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/colormatrix.rs
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image2)
+#pragma rs_fp_relaxed
+
+
+static rs_matrix4x4 Mat;
+
+void init() {
+    rsMatrixLoadIdentity(&Mat);
+}
+
+void setMatrix(rs_matrix4x4 m) {
+    Mat = m;
+}
+
+void root(const uchar4 *in, uchar4 *out) {
+    float4 f = convert_float4(*in);
+    f = rsMatrixMultiply(&Mat, f);
+    f = clamp(f, 0.f, 255.f);
+    *out = convert_uchar4(f);
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/convolve3x3.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/convolve3x3.rs
new file mode 100644
index 0000000..b55190c
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/convolve3x3.rs
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image2)
+#pragma rs_fp_relaxed
+
+int32_t gWidth;
+int32_t gHeight;
+rs_allocation gIn;
+
+float gCoeffs[9];
+
+void root(uchar4 *out, uint32_t x, uint32_t y) {
+    uint32_t x1 = min((int32_t)x+1, gWidth);
+    uint32_t x2 = max((int32_t)x-1, 0);
+    uint32_t y1 = min((int32_t)y+1, gHeight);
+    uint32_t y2 = max((int32_t)y-1, 0);
+
+    float4 p00 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x1, y1))[0]);
+    float4 p01 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x, y1))[0]);
+    float4 p02 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x2, y1))[0]);
+    float4 p10 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x1, y))[0]);
+    float4 p11 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x, y))[0]);
+    float4 p12 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x2, y))[0]);
+    float4 p20 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x1, y2))[0]);
+    float4 p21 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x, y2))[0]);
+    float4 p22 = convert_float4(((uchar4 *)rsGetElementAt(gIn, x2, y2))[0]);
+    p00 *= gCoeffs[0];
+    p01 *= gCoeffs[1];
+    p02 *= gCoeffs[2];
+    p10 *= gCoeffs[3];
+    p11 *= gCoeffs[4];
+    p12 *= gCoeffs[5];
+    p20 *= gCoeffs[6];
+    p21 *= gCoeffs[7];
+    p22 *= gCoeffs[8];
+
+    p00 += p01;
+    p02 += p10;
+    p11 += p12;
+    p20 += p21;
+
+    p22 += p00;
+    p02 += p11;
+
+    p20 += p22;
+    p20 += p02;
+
+    p20 = clamp(p20, 0.f, 255.f);
+    *out = convert_uchar4(p20);
+}
+
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye.rsh b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye.rsh
new file mode 100644
index 0000000..4dcfc1d
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye.rsh
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+rs_allocation in_alloc;
+rs_sampler sampler;
+
+static float2 center, dimensions;
+static float2 scale;
+static float alpha;
+static float radius2;
+static float factor;
+
+void init_filter(uint32_t dim_x, uint32_t dim_y, float focus_x, float focus_y, float k) {
+    center.x = focus_x;
+    center.y = focus_y;
+    dimensions.x = (float)dim_x;
+    dimensions.y = (float)dim_y;
+
+    alpha = k * 2.0 + 0.75;
+    float bound2 = 0.25;
+    if (dim_x > dim_y) {
+        scale.x = 1.0;
+        scale.y = dimensions.y / dimensions.x;
+        bound2 *= (scale.y*scale.y + 1);
+    } else {
+        scale.x = dimensions.x / dimensions.y;
+        scale.y = 1.0;
+        bound2 *= (scale.x*scale.x + 1);
+    }
+    const float bound = sqrt(bound2);
+    const float radius = 1.15 * bound;
+    radius2 = radius*radius;
+    const float max_radian = 0.5f * M_PI - atan(alpha / bound * sqrt(radius2 - bound2));
+    factor = bound / max_radian;
+}
+
+void root(uchar4 *out, uint32_t x, uint32_t y) {
+    // Convert x and y to floating point coordinates with center as origin
+    float2 coord;
+    coord.x = (float)x / dimensions.x;
+    coord.y = (float)y / dimensions.y;
+    coord -= center;
+    const float dist = length(scale * coord);
+    const float radian = M_PI_2 - atan((alpha * sqrt(radius2 - dist * dist)) / dist);
+    const float scalar = radian * factor / dist;
+    const float2 new_coord = coord * scalar + center;
+    const float4 fout = rsSample(in_alloc, sampler, new_coord);
+    *out = rsPackColorTo8888(fout);
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_full.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_full.rs
new file mode 100644
index 0000000..e42df13
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_full.rs
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image2)
+
+#include "fisheye.rsh"
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_relaxed.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_relaxed.rs
new file mode 100644
index 0000000..990310b
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/fisheye_relaxed.rs
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image2)
+#pragma rs_fp_relaxed
+
+#include "fisheye.rsh"
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/grain.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/grain.rs
new file mode 100644
index 0000000..75f4021
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/grain.rs
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image2)
+#pragma rs_fp_relaxed
+
+void genRand(uchar *out) {
+    *out = (uchar)rsRand(0xff);
+}
+
+/*
+ * Convolution matrix of distance 2 with fixed point of 'kShiftBits' bits
+ * shifted. Thus the sum of this matrix should be 'kShiftValue'. Entries of
+ * small values are not calculated to gain efficiency.
+ * The order ot pixels represented in this matrix is:
+ *  1  2  3
+ *  4  0  5
+ *  6  7  8
+ *  and the matrix should be: {230, 56, 114, 56, 114, 114, 56, 114, 56}.
+ *  However, since most of the valus are identical, we only use the first three
+ *  entries and the entries corresponding to the pixels is:
+ *  1  2  1
+ *  2  0  2
+ *  1  2  1
+ */
+
+int32_t gWidth;
+int32_t gHeight;
+
+rs_allocation gBlendSource;
+void blend9(uchar *out, uint32_t x, uint32_t y) {
+    uint32_t x1 = min(x+1, (uint32_t)gWidth);
+    uint32_t x2 = max(x-1, (uint32_t)0);
+    uint32_t y1 = min(y+1, (uint32_t)gHeight);
+    uint32_t y2 = max(y-1, (uint32_t)0);
+
+    uint p00 = 56 *  ((uchar *)rsGetElementAt(gBlendSource, x1, y1))[0];
+    uint p01 = 114 * ((uchar *)rsGetElementAt(gBlendSource, x, y1))[0];
+    uint p02 = 56 *  ((uchar *)rsGetElementAt(gBlendSource, x2, y1))[0];
+    uint p10 = 114 * ((uchar *)rsGetElementAt(gBlendSource, x1, y))[0];
+    uint p11 = 230 * ((uchar *)rsGetElementAt(gBlendSource, x, y))[0];
+    uint p12 = 114 * ((uchar *)rsGetElementAt(gBlendSource, x2, y))[0];
+    uint p20 = 56 *  ((uchar *)rsGetElementAt(gBlendSource, x1, y2))[0];
+    uint p21 = 114 * ((uchar *)rsGetElementAt(gBlendSource, x, y2))[0];
+    uint p22 = 56 *  ((uchar *)rsGetElementAt(gBlendSource, x2, y2))[0];
+
+    p00 += p01;
+    p02 += p10;
+    p11 += p12;
+    p20 += p21;
+
+    p22 += p00;
+    p02 += p11;
+
+    p20 += p22;
+    p20 += p02;
+
+    *out = (uchar)(p20 >> 10);
+}
+
+float gNoiseStrength;
+
+rs_allocation gNoise;
+void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
+    float4 ip = convert_float4(*in);
+    float pnoise = (float) ((uchar *)rsGetElementAt(gNoise, x, y))[0];
+
+    float energy_level = ip.r + ip.g + ip.b;
+    float energy_mask = (28.f - sqrt(energy_level)) * 0.03571f;
+    pnoise = (pnoise - 128.f) * energy_mask;
+
+    ip += pnoise * gNoiseStrength;
+    ip = clamp(ip, 0.f, 255.f);
+
+    uchar4 p = convert_uchar4(ip);
+    p.a = 0xff;
+    *out = p;
+}
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/greyscale.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/greyscale.rs
new file mode 100644
index 0000000..b5abf3f0
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/greyscale.rs
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image2)
+#pragma rs_fp_relaxed
+
+const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
+
+void root(const uchar4 *v_in, uchar4 *v_out) {
+    float4 f4 = rsUnpackColor8888(*v_in);
+
+    float3 mono = dot(f4.rgb, gMonoMult);
+    *v_out = rsPackColorTo8888(mono);
+}
+
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/horizontal_blur.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/horizontal_blur.rs
new file mode 100644
index 0000000..ee83496
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/horizontal_blur.rs
@@ -0,0 +1,28 @@
+#pragma version(1)
+#pragma rs_fp_relaxed
+
+#include "ip.rsh"
+
+void root(float4 *out, const void *usrData, uint32_t x, uint32_t y) {
+    const FilterStruct *fs = (const FilterStruct *)usrData;
+    float3 blurredPixel = 0;
+    const float *gPtr = fs->gaussian;
+    if ((x > fs->radius) && (x < (fs->width - fs->radius))) {
+        for (int r = -fs->radius; r <= fs->radius; r ++) {
+            const float4 *i = (const float4 *)rsGetElementAt(fs->ain, x + r, y);
+            blurredPixel += i->xyz * gPtr[0];
+            gPtr++;
+        }
+    } else {
+        for (int r = -fs->radius; r <= fs->radius; r ++) {
+            // Stepping left and right away from the pixel
+            int validX = rsClamp((int)x + r, (int)0, (int)(fs->width - 1));
+            const float4 *i = (const float4 *)rsGetElementAt(fs->ain, validX, y);
+            blurredPixel += i->xyz * gPtr[0];
+            gPtr++;
+        }
+    }
+
+    out->xyz = blurredPixel;
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ip.rsh b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ip.rsh
new file mode 100644
index 0000000..0cdf9e1
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/ip.rsh
@@ -0,0 +1,15 @@
+#pragma rs java_package_name(com.android.rs.image2)
+
+#define MAX_RADIUS 25
+
+typedef struct FilterStruct_s {
+    rs_allocation ain;
+
+    float *gaussian; //[MAX_RADIUS * 2 + 1];
+    int height;
+    int width;
+    int radius;
+
+} FilterStruct;
+
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels.rsh b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels.rsh
new file mode 100644
index 0000000..7c5d930
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels.rsh
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+float inBlack;
+float outBlack;
+float inWMinInB;
+float outWMinOutB;
+float overInWMinInB;
+rs_matrix3x3 colorMat;
+
+void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
+    float3 pixel = convert_float4(in[0]).rgb;
+    pixel = rsMatrixMultiply(&colorMat, pixel);
+    pixel = clamp(pixel, 0.f, 255.f);
+    pixel = (pixel - inBlack) * overInWMinInB;
+    pixel = pixel * outWMinOutB + outBlack;
+    pixel = clamp(pixel, 0.f, 255.f);
+    out->xyz = convert_uchar3(pixel);
+    out->w = 0xff;
+}
+
+void root4(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
+    float4 pixel = convert_float4(in[0]);
+    pixel.rgb = rsMatrixMultiply(&colorMat, pixel.rgb);
+    pixel = clamp(pixel, 0.f, 255.f);
+    pixel = (pixel - inBlack) * overInWMinInB;
+    pixel = pixel * outWMinOutB + outBlack;
+    pixel = clamp(pixel, 0.f, 255.f);
+    out->xyzw = convert_uchar4(pixel);
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels_full.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels_full.rs
new file mode 100644
index 0000000..a4aa388
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels_full.rs
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image2)
+
+#include "levels.rsh"
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels_relaxed.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels_relaxed.rs
new file mode 100644
index 0000000..ffdcfe3
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/levels_relaxed.rs
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image2)
+#pragma rs_fp_relaxed
+
+#include "levels.rsh"
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/threshold.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/threshold.rs
new file mode 100644
index 0000000..77cd5be
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/threshold.rs
@@ -0,0 +1,93 @@
+#pragma version(1)
+
+#include "ip.rsh"
+
+int height;
+int width;
+int radius;
+
+uchar4 * InPixel;
+uchar4 * OutPixel;
+float4 * ScratchPixel1;
+float4 * ScratchPixel2;
+
+rs_script vBlurScript;
+rs_script hBlurScript;
+
+const int CMD_FINISHED = 1;
+
+// Store our coefficients here
+static float gaussian[MAX_RADIUS * 2 + 1];
+
+
+static void computeGaussianWeights() {
+    // Compute gaussian weights for the blur
+    // e is the euler's number
+    float e = 2.718281828459045f;
+    float pi = 3.1415926535897932f;
+    // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
+    // x is of the form [-radius .. 0 .. radius]
+    // and sigma varies with radius.
+    // Based on some experimental radius values and sigma's
+    // we approximately fit sigma = f(radius) as
+    // sigma = radius * 0.4  + 0.6
+    // The larger the radius gets, the more our gaussian blur
+    // will resemble a box blur since with large sigma
+    // the gaussian curve begins to lose its shape
+    float sigma = 0.4f * (float)radius + 0.6f;
+
+    // Now compute the coefficints
+    // We will store some redundant values to save some math during
+    // the blur calculations
+    // precompute some values
+    float coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
+    float coeff2 = - 1.0f / (2.0f * sigma * sigma);
+
+    float normalizeFactor = 0.0f;
+    float floatR = 0.0f;
+    int r;
+    for (r = -radius; r <= radius; r ++) {
+        floatR = (float)r;
+        gaussian[r + radius] = coeff1 * pow(e, floatR * floatR * coeff2);
+        normalizeFactor += gaussian[r + radius];
+    }
+
+    //Now we need to normalize the weights because all our coefficients need to add up to one
+    normalizeFactor = 1.0f / normalizeFactor;
+    for (r = -radius; r <= radius; r ++) {
+        floatR = (float)r;
+        gaussian[r + radius] *= normalizeFactor;
+    }
+}
+
+
+static void copyInput() {
+    rs_allocation ain;
+    ain = rsGetAllocation(InPixel);
+    uint32_t dimx = rsAllocationGetDimX(ain);
+    uint32_t dimy = rsAllocationGetDimY(ain);
+    for (uint32_t y = 0; y < dimy; y++) {
+        for (uint32_t x = 0; x < dimx; x++) {
+            ScratchPixel1[x + y * dimx] = convert_float4(InPixel[x + y * dimx]);
+        }
+    }
+}
+
+void filter() {
+    copyInput();
+    computeGaussianWeights();
+
+    FilterStruct fs;
+    fs.gaussian = gaussian;
+    fs.width = width;
+    fs.height = height;
+    fs.radius = radius;
+
+    fs.ain = rsGetAllocation(ScratchPixel1);
+    rsForEach(hBlurScript, fs.ain, rsGetAllocation(ScratchPixel2), &fs, sizeof(fs));
+
+    fs.ain = rsGetAllocation(ScratchPixel2);
+    rsForEach(vBlurScript, fs.ain, rsGetAllocation(OutPixel), &fs, sizeof(fs));
+    //rsSendToClientBlocking(CMD_FINISHED);
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vertical_blur.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vertical_blur.rs
new file mode 100644
index 0000000..60fd71b
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vertical_blur.rs
@@ -0,0 +1,59 @@
+#pragma version(1)
+#pragma rs_fp_relaxed
+
+#include "ip.rsh"
+
+static float saturation;
+static rs_matrix3x3 colorMat;
+
+void setSaturation(float sat) {
+    saturation = sat;
+
+    // Saturation
+    // Linear weights
+    //float rWeight = 0.3086f;
+    //float gWeight = 0.6094f;
+    //float bWeight = 0.0820f;
+
+    // Gamma 2.2 weights (we haven't converted our image to linear space yet for perf reasons)
+    float rWeight = 0.299f;
+    float gWeight = 0.587f;
+    float bWeight = 0.114f;
+
+    float oneMinusS = 1.0f - saturation;
+    rsMatrixSet(&colorMat, 0, 0, oneMinusS * rWeight + saturation);
+    rsMatrixSet(&colorMat, 0, 1, oneMinusS * rWeight);
+    rsMatrixSet(&colorMat, 0, 2, oneMinusS * rWeight);
+    rsMatrixSet(&colorMat, 1, 0, oneMinusS * gWeight);
+    rsMatrixSet(&colorMat, 1, 1, oneMinusS * gWeight + saturation);
+    rsMatrixSet(&colorMat, 1, 2, oneMinusS * gWeight);
+    rsMatrixSet(&colorMat, 2, 0, oneMinusS * bWeight);
+    rsMatrixSet(&colorMat, 2, 1, oneMinusS * bWeight);
+    rsMatrixSet(&colorMat, 2, 2, oneMinusS * bWeight + saturation);
+}
+
+void root(uchar4 *out, const void *usrData, uint32_t x, uint32_t y) {
+    const FilterStruct *fs = (const FilterStruct *)usrData;
+    float3 blurredPixel = 0;
+    const float *gPtr = fs->gaussian;
+    if ((y > fs->radius) && (y < (fs->height - fs->radius))) {
+        for (int r = -fs->radius; r <= fs->radius; r ++) {
+            const float4 *i = (const float4 *)rsGetElementAt(fs->ain, x, y + r);
+            blurredPixel += i->xyz * gPtr[0];
+            gPtr++;
+        }
+    } else {
+        for (int r = -fs->radius; r <= fs->radius; r ++) {
+            int validH = rsClamp((int)y + r, (int)0, (int)(fs->height - 1));
+            const float4 *i = (const float4 *)rsGetElementAt(fs->ain, x, validH);
+            blurredPixel += i->xyz * gPtr[0];
+            gPtr++;
+        }
+    }
+
+    float3 temp = rsMatrixMultiply(&colorMat, blurredPixel);
+    temp = clamp(temp, 0.f, 255.f);
+    out->xyz = convert_uchar3(temp);
+    out->w = 0xff;
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette.rsh b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette.rsh
new file mode 100644
index 0000000..a1e4ae5
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette.rsh
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+static float2 neg_center, axis_scale, inv_dimensions;
+static float sloped_neg_range, sloped_inv_max_dist, shade, opp_shade;
+
+void init_vignette(uint32_t dim_x, uint32_t dim_y, float center_x, float center_y,
+        float desired_scale, float desired_shade, float desired_slope) {
+
+    neg_center.x = -center_x;
+    neg_center.y = -center_y;
+    inv_dimensions.x = 1.f / (float)dim_x;
+    inv_dimensions.y = 1.f / (float)dim_y;
+
+    axis_scale = (float2)1.f;
+    if (dim_x > dim_y)
+        axis_scale.y = (float)dim_y / (float)dim_x;
+    else
+        axis_scale.x = (float)dim_x / (float)dim_y;
+
+    const float max_dist = 0.5 * length(axis_scale);
+    sloped_inv_max_dist = desired_slope * 1.f/max_dist;
+
+    // Range needs to be between 1.3 to 0.6. When scale is zero then range is
+    // 1.3 which means no vignette at all because the luminousity difference is
+    // less than 1/256.  Expect input scale to be between 0.0 and 1.0.
+    const float neg_range = 0.7*sqrt(desired_scale) - 1.3;
+    sloped_neg_range = exp(neg_range * desired_slope);
+
+    shade = desired_shade;
+    opp_shade = 1.f - desired_shade;
+}
+
+void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) {
+    // Convert x and y to floating point coordinates with center as origin
+    const float4 fin = convert_float4(*in);
+    const float2 inCoord = {(float)x, (float)y};
+    const float2 coord = mad(inCoord, inv_dimensions, neg_center);
+    const float sloped_dist_ratio = length(axis_scale * coord)  * sloped_inv_max_dist;
+    const float lumen = opp_shade + shade / ( 1.0 + sloped_neg_range * exp(sloped_dist_ratio) );
+    float4 fout;
+    fout.rgb = fin.rgb * lumen;
+    fout.w = fin.w;
+    *out = convert_uchar4(fout);
+}
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_full.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_full.rs
new file mode 100644
index 0000000..5fc2dda
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_full.rs
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image2)
+
+#include "vignette.rsh"
+
diff --git a/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_relaxed.rs b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_relaxed.rs
new file mode 100644
index 0000000..430b685
--- /dev/null
+++ b/tests/RenderScriptTests/ImageProcessing2/src/com/android/rs/image/vignette_relaxed.rs
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.rs.image2)
+#pragma rs_fp_relaxed
+
+#include "vignette.rsh"
+
diff --git a/tests/StatusBar/src/com/android/statusbartest/PowerTest.java b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
index 31a1cf5a..e38bb6c 100644
--- a/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
@@ -16,32 +16,15 @@
 
 package com.android.statusbartest;
 
-import android.app.ListActivity;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.widget.ArrayAdapter;
-import android.view.View;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.IPowerManager;
-import android.widget.ListView;
-import android.content.Intent;
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.StatusBarManager;
 import android.os.RemoteException;
-import android.os.Vibrator;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.LocalPowerManager;
 import android.os.ServiceManager;
-import android.util.Log;
-import android.net.Uri;
-import android.os.SystemClock;
-import android.widget.RemoteViews;
-import android.widget.Toast;
 import android.os.PowerManager;
 
 public class PowerTest extends TestActivity
@@ -101,6 +84,28 @@
                 mProx.release(PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);
             }
         },
+        new Test("Enable proximity, wait 5 seconds then disable") {
+            public void run() {
+                mProx.acquire();
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        mProx.release();
+                    }
+                }, 5000);
+            }
+        },
+        new Test("Enable proximity, wait 5 seconds then disable  (WAIT_FOR_PROXIMITY_NEGATIVE)") {
+            public void run() {
+                mProx.acquire();
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        mProx.release(PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);
+                    }
+                }, 5000);
+            }
+        },
         new Test("Touch events don't poke") {
             public void run() {
                 mPokeState |= LocalPowerManager.POKE_LOCK_IGNORE_TOUCH_EVENTS;
diff --git a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
index 97d9969..4901f72 100644
--- a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
+++ b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
@@ -19,6 +19,7 @@
 import com.android.layoutlib.bridge.android.BridgeWindow;
 import com.android.layoutlib.bridge.android.BridgeWindowSession;
 
+import android.content.Context;
 import android.os.Handler;
 import android.view.View.AttachInfo;
 
@@ -28,8 +29,12 @@
 public class AttachInfo_Accessor {
 
     public static void setAttachInfo(View view) {
+        Context context = view.getContext();
+        WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
+        Display display = wm.getDefaultDisplay();
+        ViewRootImpl root = new ViewRootImpl(context, display);
         AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(),
-                new ViewRootImpl(view.getContext()), new Handler(), null);
+                display, root, new Handler(), null);
         info.mHasWindowFocus = true;
         info.mWindowVisibility = View.VISIBLE;
         info.mInTouchMode = false; // this is so that we can display selections.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index c4a6906..3d45bff 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -61,10 +61,12 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
+import android.os.UserHandle;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
 import android.view.BridgeInflater;
+import android.view.CompatibilityInfoHolder;
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewGroup;
@@ -440,7 +442,7 @@
         }
 
         if (POWER_SERVICE.equals(service)) {
-            return new PowerManager(new BridgePowerManager(), new Handler());
+            return new PowerManager(this, new BridgePowerManager(), new Handler());
         }
 
         throw new UnsupportedOperationException("Unsupported Service: " + service);
@@ -917,6 +919,12 @@
     }
 
     @Override
+    public Context createConfigurationContext(Configuration overrideConfiguration) {
+        // pass
+        return null;
+    }
+
+    @Override
     public String[] databaseList() {
         // pass
         return null;
@@ -1187,12 +1195,12 @@
     }
 
     @Override
-    public void sendBroadcastToUser(Intent intent, int userId) {
+    public void sendBroadcastAsUser(Intent intent, UserHandle user) {
         // pass
     }
 
     @Override
-    public void sendOrderedBroadcastToUser(Intent intent, int userId,
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
             BroadcastReceiver resultReceiver, Handler scheduler,
             int initialCode, String initialData, Bundle initialExtras) {
         // pass
@@ -1311,4 +1319,10 @@
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null);
         return null;
     }
+
+    @Override
+    public CompatibilityInfoHolder getCompatibilityInfo() {
+        // pass
+        return null;
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
index 6071a6b..0c85204 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePowerManager.java
@@ -39,7 +39,7 @@
     }
 
     @Override
-    public void acquireWakeLock(int arg0, IBinder arg1, String arg2, WorkSource arg3)
+    public void acquireWakeLock(IBinder arg0, int arg1, String arg2, WorkSource arg3)
             throws RemoteException {
         // pass for now.
     }
@@ -55,18 +55,7 @@
     }
 
     @Override
-    public int getSupportedWakeLockFlags() throws RemoteException {
-        // pass for now.
-        return 0;
-    }
-
-    @Override
-    public void goToSleep(long arg0) throws RemoteException {
-        // pass for now.
-    }
-
-    @Override
-    public void goToSleepWithReason(long arg0, int arg1) throws RemoteException {
+    public void goToSleep(long arg0, int arg1) throws RemoteException {
         // pass for now.
     }
 
@@ -91,17 +80,17 @@
     }
 
     @Override
-    public void setAutoBrightnessAdjustment(float arg0) throws RemoteException {
+    public void setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(float arg0) throws RemoteException {
         // pass for now.
     }
 
     @Override
-    public void setBacklightBrightness(int arg0) throws RemoteException {
+    public void setTemporaryScreenBrightnessSettingOverride(int arg0) throws RemoteException {
         // pass for now.
     }
 
     @Override
-    public void setMaximumScreenOffTimeount(int arg0) throws RemoteException {
+    public void setMaximumScreenOffTimeoutFromDeviceAdmin(int arg0) throws RemoteException {
         // pass for now.
     }
 
@@ -121,12 +110,18 @@
     }
 
     @Override
-    public void userActivity(long arg0, boolean arg1) throws RemoteException {
+    public boolean isWakeLockLevelSupported(int level) throws RemoteException {
+        // pass for now.
+        return true;
+    }
+
+    @Override
+    public void userActivity(long time, int event, int flags) throws RemoteException {
         // pass for now.
     }
 
     @Override
-    public void userActivityWithForce(long arg0, boolean arg1, boolean arg2) throws RemoteException {
+    public void wakeUp(long time) throws RemoteException {
         // pass for now.
     }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index f548b46..5516339 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -225,7 +225,7 @@
 
     @Override
     public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
-            IRemoteCallback startedCallback, boolean delayed) throws RemoteException {
+            IRemoteCallback startedCallback, boolean scaleUp) throws RemoteException {
         // TODO Auto-generated method stub
     }
 
diff --git a/wifi/java/android/net/wifi/RssiPacketCountInfo.java b/wifi/java/android/net/wifi/RssiPacketCountInfo.java
new file mode 100644
index 0000000..f549e1d
--- /dev/null
+++ b/wifi/java/android/net/wifi/RssiPacketCountInfo.java
@@ -0,0 +1,71 @@
+/*
+ * 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.net.wifi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Bundle of RSSI and packet count information, for WiFi watchdog
+ *
+ * @see WifiWatchdogStateMachine
+ *
+ * @hide
+ */
+public class RssiPacketCountInfo implements Parcelable {
+
+    public int rssi;
+
+    public int txgood;
+
+    public int txbad;
+
+    public RssiPacketCountInfo() {
+        rssi = txgood = txbad = 0;
+    }
+
+    private RssiPacketCountInfo(Parcel in) {
+        rssi = in.readInt();
+        txgood = in.readInt();
+        txbad = in.readInt();
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(rssi);
+        out.writeInt(txgood);
+        out.writeInt(txbad);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<RssiPacketCountInfo> CREATOR =
+            new Parcelable.Creator<RssiPacketCountInfo>() {
+        @Override
+        public RssiPacketCountInfo createFromParcel(Parcel in) {
+            return new RssiPacketCountInfo(in);
+        }
+
+        @Override
+        public RssiPacketCountInfo[] newArray(int size) {
+            return new RssiPacketCountInfo[size];
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 32261de..3e20756 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -47,19 +47,37 @@
     public int frequency;
 
     /**
+     * Time Synchronization Function (tsf) timestamp in microseconds when
+     * this result was last seen.
+     */
+     public long timestamp;
+
+    /**
      * We'd like to obtain the following attributes,
      * but they are not reported via the socket
      * interface, even though they are known
      * internally by wpa_supplicant.
      * {@hide}
      */
-    public ScanResult(String SSID, String BSSID, String caps, int level, int frequency) {
+    public ScanResult(String SSID, String BSSID, String caps, int level, int frequency, long tsf) {
         this.SSID = SSID;
         this.BSSID = BSSID;
         this.capabilities = caps;
         this.level = level;
         this.frequency = frequency;
-        //networkConfig = null;
+        this.timestamp = tsf;
+    }
+
+    /** copy constructor {@hide} */
+    public ScanResult(ScanResult source) {
+        if (source != null) {
+            SSID = source.SSID;
+            BSSID = source.BSSID;
+            capabilities = source.capabilities;
+            level = source.level;
+            frequency = source.frequency;
+            timestamp = source.timestamp;
+        }
     }
 
     @Override
@@ -76,7 +94,9 @@
             append(", level: ").
             append(level).
             append(", frequency: ").
-            append(frequency);
+            append(frequency).
+            append(", timestamp: ").
+            append(timestamp);
 
         return sb.toString();
     }
@@ -93,6 +113,7 @@
         dest.writeString(capabilities);
         dest.writeInt(level);
         dest.writeInt(frequency);
+        dest.writeLong(timestamp);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -104,7 +125,8 @@
                     in.readString(),
                     in.readString(),
                     in.readInt(),
-                    in.readInt()
+                    in.readInt(),
+                    in.readLong()
                 );
             }
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 6e58a2d..3579b86 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -906,6 +906,17 @@
     }
 
     /**
+     * Return TX packet counter, for CTS test of WiFi watchdog.
+     * @param listener is the interface to receive result
+     *
+     * @hide for CTS test only
+     */
+    public void getTxPacketCount(TxPacketCountListener listener) {
+        validateChannel();
+        mAsyncChannel.sendMessage(RSSI_PKTCNT_FETCH, 0, putListener(listener));
+    }
+
+    /**
      * Calculates the level of the signal. This should be used any time a signal
      * is being shown.
      *
@@ -1143,11 +1154,18 @@
     /** @hide */
     public static final int DISABLE_NETWORK_SUCCEEDED       = BASE + 19;
 
+    /** @hide */
+    public static final int RSSI_PKTCNT_FETCH               = BASE + 20;
+    /** @hide */
+    public static final int RSSI_PKTCNT_FETCH_SUCCEEDED     = BASE + 21;
+    /** @hide */
+    public static final int RSSI_PKTCNT_FETCH_FAILED        = BASE + 22;
+
     /* For system use only */
     /** @hide */
-    public static final int ENABLE_TRAFFIC_STATS_POLL       = BASE + 21;
+    public static final int ENABLE_TRAFFIC_STATS_POLL       = BASE + 31;
     /** @hide */
-    public static final int TRAFFIC_STATS_POLL              = BASE + 22;
+    public static final int TRAFFIC_STATS_POLL              = BASE + 32;
 
 
     /**
@@ -1212,6 +1230,21 @@
         public void onFailure(int reason);
     }
 
+    /** Interface for callback invocation on a TX packet count poll action {@hide} */
+    public interface TxPacketCountListener {
+        /**
+         * The operation succeeded
+         * @param count TX packet counter
+         */
+        public void onSuccess(int count);
+        /**
+         * The operation failed
+         * @param reason The reason for failure could be one of
+         * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
+         */
+        public void onFailure(int reason);
+    }
+
     private class ServiceHandler extends Handler {
         ServiceHandler(Looper looper) {
             super(looper);
@@ -1281,6 +1314,20 @@
                         ((WpsListener) listener).onFailure(message.arg1);
                     }
                     break;
+                case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED:
+                    if (listener != null) {
+                        RssiPacketCountInfo info = (RssiPacketCountInfo) message.obj;
+                        if (info != null)
+                            ((TxPacketCountListener) listener).onSuccess(info.txgood + info.txbad);
+                        else
+                            ((TxPacketCountListener) listener).onFailure(ERROR);
+                    }
+                    break;
+                case WifiManager.RSSI_PKTCNT_FETCH_FAILED:
+                    if (listener != null) {
+                        ((TxPacketCountListener) listener).onFailure(message.arg1);
+                    }
+                    break;
                 default:
                     //ignore
                     break;
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 84c565b..1b7e378 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -197,8 +197,22 @@
         return null;
     }
 
+    /**
+     * Format of results:
+     * =================
+     * bssid=68:7f:74:d7:1b:6e
+     * freq=2412
+     * level=-43
+     * tsf=1344621975160944
+     * age=2623
+     * flags=[WPA2-PSK-CCMP][WPS][ESS]
+     * ssid=zubyb
+     *
+     * RANGE=ALL gets all scan results
+     * MASK=<N> see wpa_supplicant/src/common/wpa_ctrl.h for details
+     */
     public String scanResults() {
-        return doStringCommand("SCAN_RESULTS");
+        return doStringCommand("BSS RANGE=ALL MASK=0x1986");
     }
 
     public boolean startDriver() {
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index a8975ff..1d06c76 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -52,7 +52,7 @@
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkUtils;
-import android.net.wifi.WifiWatchdogStateMachine.RssiPktcntStat;
+import android.net.wifi.RssiPacketCountInfo;
 import android.net.wifi.WpsResult.Status;
 import android.net.wifi.p2p.WifiP2pManager;
 import android.net.wifi.p2p.WifiP2pService;
@@ -114,7 +114,7 @@
     private final String mPrimaryDeviceType;
 
     /* Scan results handling */
-    private List<ScanResult> mScanResults;
+    private List<ScanResult> mScanResults = new ArrayList<ScanResult>();
     private static final Pattern scanResultPattern = Pattern.compile("\t+");
     private static final int SCAN_RESULT_CACHE_SIZE = 80;
     private final LruCache<String, ScanResult> mScanResultCache;
@@ -891,7 +891,13 @@
      * TODO: doc
      */
     public List<ScanResult> syncGetScanResultsList() {
-        return mScanResults;
+        synchronized (mScanResultCache) {
+            List<ScanResult> scanList = new ArrayList<ScanResult>();
+            for(ScanResult result: mScanResults) {
+                scanList.add(new ScanResult(result));
+            }
+            return scanList;
+        }
     }
 
     /**
@@ -1189,7 +1195,7 @@
             case CMD_RSSI_POLL:
             case CMD_DELAYED_STOP_DRIVER:
             case WifiMonitor.SCAN_RESULTS_EVENT:
-            case WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH:
+            case WifiManager.RSSI_PKTCNT_FETCH:
                 return false;
             default:
                 return true;
@@ -1255,14 +1261,14 @@
            ip settings */
         InterfaceConfiguration ifcg = null;
         try {
-            ifcg = mNwService.getInterfaceConfig(mInterfaceName);
+            ifcg = mNwService.getInterfaceConfig(mTetherInterfaceName);
             if (ifcg != null) {
                 ifcg.setLinkAddress(
                         new LinkAddress(NetworkUtils.numericToInetAddress("0.0.0.0"), 0));
-                mNwService.setInterfaceConfig(mInterfaceName, ifcg);
+                mNwService.setInterfaceConfig(mTetherInterfaceName, ifcg);
             }
         } catch (Exception e) {
-            loge("Error resetting interface " + mInterfaceName + ", :" + e);
+            loge("Error resetting interface " + mTetherInterfaceName + ", :" + e);
         }
 
         if (mCm.untether(mTetherInterfaceName) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
@@ -1357,131 +1363,103 @@
         mContext.sendStickyBroadcast(intent);
     }
 
+    private static final String BSSID_STR = "bssid=";
+    private static final String FREQ_STR = "freq=";
+    private static final String LEVEL_STR = "level=";
+    private static final String TSF_STR = "tsf=";
+    private static final String FLAGS_STR = "flags=";
+    private static final String SSID_STR = "ssid=";
+    private static final String DELIMITER_STR = "====";
     /**
-     * Parse the scan result line passed to us by wpa_supplicant (helper).
-     * @param line the line to parse
-     * @return the {@link ScanResult} object
-     */
-    private ScanResult parseScanResult(String line) {
-        ScanResult scanResult = null;
-        if (line != null) {
-            /*
-             * Cache implementation (LinkedHashMap) is not synchronized, thus,
-             * must synchronized here!
-             */
-            synchronized (mScanResultCache) {
-                String[] result = scanResultPattern.split(line);
-                if (3 <= result.length && result.length <= 5) {
-                    String bssid = result[0];
-                    // bssid | frequency | level | flags | ssid
-                    int frequency;
-                    int level;
-                    try {
-                        frequency = Integer.parseInt(result[1]);
-                        level = Integer.parseInt(result[2]);
-                        /* some implementations avoid negative values by adding 256
-                         * so we need to adjust for that here.
-                         */
-                        if (level > 0) level -= 256;
-                    } catch (NumberFormatException e) {
-                        frequency = 0;
-                        level = 0;
-                    }
-
-                    /*
-                     * The formatting of the results returned by
-                     * wpa_supplicant is intended to make the fields
-                     * line up nicely when printed,
-                     * not to make them easy to parse. So we have to
-                     * apply some heuristics to figure out which field
-                     * is the SSID and which field is the flags.
-                     */
-                    String ssid;
-                    String flags;
-                    if (result.length == 4) {
-                        if (result[3].charAt(0) == '[') {
-                            flags = result[3];
-                            ssid = "";
-                        } else {
-                            flags = "";
-                            ssid = result[3];
-                        }
-                    } else if (result.length == 5) {
-                        flags = result[3];
-                        ssid = result[4];
-                    } else {
-                        // Here, we must have 3 fields: no flags and ssid
-                        // set
-                        flags = "";
-                        ssid = "";
-                    }
-
-                    // bssid + ssid is the hash key
-                    String key = bssid + ssid;
-                    scanResult = mScanResultCache.get(key);
-                    if (scanResult != null) {
-                        scanResult.level = level;
-                        scanResult.SSID = ssid;
-                        scanResult.capabilities = flags;
-                        scanResult.frequency = frequency;
-                    } else {
-                        // Do not add scan results that have no SSID set
-                        if (0 < ssid.trim().length()) {
-                            scanResult =
-                                new ScanResult(
-                                    ssid, bssid, flags, level, frequency);
-                            mScanResultCache.put(key, scanResult);
-                        }
-                    }
-                } else {
-                    loge("Misformatted scan result text with " +
-                          result.length + " fields: " + line);
-                }
-            }
-        }
-
-        return scanResult;
-    }
-
-    /**
-     * scanResults input format
-     * 00:bb:cc:dd:cc:ee       2427    166     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net1
-     * 00:bb:cc:dd:cc:ff       2412    165     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net2
+     * Format:
+     * bssid=68:7f:76:d7:1a:6e
+     * freq=2412
+     * level=-44
+     * tsf=1344626243700342
+     * flags=[WPA2-PSK-CCMP][WPS][ESS]
+     * ssid=zfdy
+     * ====
+     * bssid=68:5f:74:d7:1a:6f
+     * freq=5180
+     * level=-73
+     * tsf=1344626243700373
+     * flags=[WPA2-PSK-CCMP][WPS][ESS]
+     * ssid=zuby
+     * ====
      */
     private void setScanResults(String scanResults) {
+        String bssid = "";
+        int level = 0;
+        int freq = 0;
+        long tsf = 0;
+        String flags = "";
+        String ssid = "";
+
         if (scanResults == null) {
             return;
         }
 
-        List<ScanResult> scanList = new ArrayList<ScanResult>();
+        synchronized(mScanResultCache) {
+            mScanResults = new ArrayList<ScanResult>();
+            String[] lines = scanResults.split("\n");
 
-        int lineCount = 0;
-
-        int scanResultsLen = scanResults.length();
-        // Parse the result string, keeping in mind that the last line does
-        // not end with a newline.
-        for (int lineBeg = 0, lineEnd = 0; lineEnd <= scanResultsLen; ++lineEnd) {
-            if (lineEnd == scanResultsLen || scanResults.charAt(lineEnd) == '\n') {
-                ++lineCount;
-
-                if (lineCount == 1) {
-                    lineBeg = lineEnd + 1;
-                    continue;
-                }
-                if (lineEnd > lineBeg) {
-                    String line = scanResults.substring(lineBeg, lineEnd);
-                    ScanResult scanResult = parseScanResult(line);
-                    if (scanResult != null) {
-                        scanList.add(scanResult);
-                    } else {
-                        //TODO: hidden network handling
+            for (String line : lines) {
+                if (line.startsWith(BSSID_STR)) {
+                    bssid = line.substring(BSSID_STR.length());
+                } else if (line.startsWith(FREQ_STR)) {
+                    try {
+                        freq = Integer.parseInt(line.substring(FREQ_STR.length()));
+                    } catch (NumberFormatException e) {
+                        freq = 0;
                     }
+                } else if (line.startsWith(LEVEL_STR)) {
+                    try {
+                        level = Integer.parseInt(line.substring(LEVEL_STR.length()));
+                        /* some implementations avoid negative values by adding 256
+                         * so we need to adjust for that here.
+                         */
+                        if (level > 0) level -= 256;
+                    } catch(NumberFormatException e) {
+                        level = 0;
+                    }
+                } else if (line.startsWith(TSF_STR)) {
+                    try {
+                        tsf = Long.parseLong(line.substring(TSF_STR.length()));
+                    } catch (NumberFormatException e) {
+                        tsf = 0;
+                    }
+                } else if (line.startsWith(FLAGS_STR)) {
+                    flags = line.substring(FLAGS_STR.length());
+                } else if (line.startsWith(SSID_STR)) {
+                    ssid = line.substring(SSID_STR.length());
+                    if (ssid == null) ssid = "";
+                } else if (line.startsWith(DELIMITER_STR)) {
+                    if (bssid != null) {
+                        String key = bssid + ssid;
+                        ScanResult scanResult = mScanResultCache.get(key);
+                        if (scanResult != null) {
+                            scanResult.level = level;
+                            scanResult.SSID = ssid;
+                            scanResult.capabilities = flags;
+                            scanResult.frequency = freq;
+                            scanResult.timestamp = tsf;
+                        } else {
+                            scanResult =
+                                new ScanResult(
+                                        ssid, bssid, flags, level, freq, tsf);
+                            mScanResultCache.put(key, scanResult);
+                        }
+                        mScanResults.add(scanResult);
+                    }
+                    bssid = null;
+                    level = 0;
+                    freq = 0;
+                    tsf = 0;
+                    flags = "";
+                    ssid = "";
                 }
-                lineBeg = lineEnd + 1;
             }
         }
-
-        mScanResults = scanList;
     }
 
     /*
@@ -1543,7 +1521,7 @@
     /*
      * Fetch TX packet counters on current connection
      */
-    private void fetchPktcntNative(RssiPktcntStat stat) {
+    private void fetchPktcntNative(RssiPacketCountInfo info) {
         String pktcntPoll = mWifiNative.pktcntPoll();
 
         if (pktcntPoll != null) {
@@ -1553,9 +1531,9 @@
                 if (prop.length < 2) continue;
                 try {
                     if (prop[0].equals("TXGOOD")) {
-                        stat.txgood = Integer.parseInt(prop[1]);
+                        info.txgood = Integer.parseInt(prop[1]);
                     } else if (prop[0].equals("TXBAD")) {
-                        stat.txbad = Integer.parseInt(prop[1]);
+                        info.txbad = Integer.parseInt(prop[1]);
                     }
                 } catch (NumberFormatException e) {
                     //Ignore
@@ -1972,8 +1950,9 @@
                     replyToMessage(message, WifiManager.DISABLE_NETWORK_FAILED,
                             WifiManager.BUSY);
                     break;
-                case WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH:
-                    replyToMessage(message, WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH_FAILED);
+                case WifiManager.RSSI_PKTCNT_FETCH:
+                    replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_FAILED,
+                            WifiManager.BUSY);
                     break;
                 default:
                     loge("Error! unhandled message" + message);
@@ -2827,7 +2806,7 @@
             if (DBG) log(getName() + "\n");
             mIsRunning = false;
             updateBatteryWorkSource(null);
-            mScanResults = null;
+            mScanResults = new ArrayList<ScanResult>();
 
             if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P);
             mContext.unregisterReceiver(mScreenReceiver);
@@ -3176,13 +3155,12 @@
                                 mRssiPollToken, 0), POLL_RSSI_INTERVAL_MSECS);
                     }
                     break;
-                case WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH:
-                    RssiPktcntStat stat = (RssiPktcntStat) message.obj;
+                case WifiManager.RSSI_PKTCNT_FETCH:
+                    RssiPacketCountInfo info = new RssiPacketCountInfo();
                     fetchRssiAndLinkSpeedNative();
-                    stat.rssi = mWifiInfo.getRssi();
-                    fetchPktcntNative(stat);
-                    replyToMessage(message, WifiWatchdogStateMachine.RSSI_PKTCNT_FETCH_SUCCEEDED,
-                            stat);
+                    info.rssi = mWifiInfo.getRssi();
+                    fetchPktcntNative(info);
+                    replyToMessage(message, WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED, info);
                     break;
                 default:
                     return NOT_HANDLED;
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index 7b4d113..29a53b6 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -30,6 +30,7 @@
 import android.net.LinkProperties;
 import android.net.NetworkInfo;
 import android.net.Uri;
+import android.net.wifi.RssiPacketCountInfo;
 import android.os.Message;
 import android.os.SystemClock;
 import android.provider.Settings;
@@ -105,9 +106,6 @@
     /* Notifications from/to WifiStateMachine */
     static final int POOR_LINK_DETECTED                             = BASE + 21;
     static final int GOOD_LINK_DETECTED                             = BASE + 22;
-    static final int RSSI_PKTCNT_FETCH                              = BASE + 23;
-    static final int RSSI_PKTCNT_FETCH_SUCCEEDED                    = BASE + 24;
-    static final int RSSI_PKTCNT_FETCH_FAILED                       = BASE + 25;
 
     /*
      * RSSI levels as used by notification icon
@@ -123,7 +121,7 @@
      * <p>
      * Larger threshold is more adaptive but increases sampling cost.
      */
-    private static final int LINK_MONITOR_LEVEL_THRESHOLD = 4;
+    private static final int LINK_MONITOR_LEVEL_THRESHOLD = WifiManager.RSSI_LEVELS - 1;
 
     /**
      * Remember packet loss statistics of how many BSSIDs.
@@ -228,8 +226,8 @@
      * Adaptive good link target to avoid flapping.
      * When a poor link is detected, a good link target is calculated as follows:
      * <p>
-     *      targetRSSI = min{ rssi | loss(rssi) < GOOD_LINK_LOSS_THRESHOLD } + rssi_adj[i],
-     *                   where rssi is in the above GOOD_LINK_RSSI_RANGE.
+     *      targetRSSI = min { rssi | loss(rssi) < GOOD_LINK_LOSS_THRESHOLD } + rssi_adj[i],
+     *                   where rssi is within the above GOOD_LINK_RSSI_RANGE.
      *      targetCount = sample_count[i] .
      * <p>
      * While WiFi is being avoided, we keep monitoring its signal strength.
@@ -241,7 +239,7 @@
      * <p>
      * Intuitively, larger index i makes it more difficult to get back to WiFi, avoiding flapping.
      * In experiments, (+9 dB / 30 counts) makes it quite difficult to achieve.
-     * Avoid using it unless flapping is really bad (say, last poor link is only 1min ago).
+     * Avoid using it unless flapping is really bad (say, last poor link is < 1 min ago).
      */
     private static final GoodLinkTarget[] GOOD_LINK_TARGET = {
         /*                  rssi_adj,       sample_count,   reduce_time */
@@ -591,8 +589,8 @@
                 case EVENT_BSSID_CHANGE:
                 case CMD_DELAYED_WALLED_GARDEN_CHECK:
                 case CMD_RSSI_FETCH:
-                case RSSI_PKTCNT_FETCH_SUCCEEDED:
-                case RSSI_PKTCNT_FETCH_FAILED:
+                case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED:
+                case WifiManager.RSSI_PKTCNT_FETCH_FAILED:
                     // ignore
                     break;
                 case EVENT_SCREEN_ON:
@@ -764,15 +762,15 @@
 
                 case CMD_RSSI_FETCH:
                     if (msg.arg1 == mRssiFetchToken) {
-                        mWsmChannel.sendMessage(RSSI_PKTCNT_FETCH, new RssiPktcntStat());
+                        mWsmChannel.sendMessage(WifiManager.RSSI_PKTCNT_FETCH);
                         sendMessageDelayed(obtainMessage(CMD_RSSI_FETCH, ++mRssiFetchToken, 0),
                                 LINK_SAMPLING_INTERVAL_MS);
                     }
                     break;
 
-                case RSSI_PKTCNT_FETCH_SUCCEEDED:
-                    RssiPktcntStat stat = (RssiPktcntStat) msg.obj;
-                    int rssi = stat.rssi;
+                case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED:
+                    RssiPacketCountInfo info = (RssiPacketCountInfo) msg.obj;
+                    int rssi = info.rssi;
                     if (DBG) logd("Fetch RSSI succeed, rssi=" + rssi);
 
                     long time = mCurrentBssid.mBssidAvoidTimeMax - SystemClock.elapsedRealtime();
@@ -795,7 +793,7 @@
                     }
                     break;
 
-                case RSSI_PKTCNT_FETCH_FAILED:
+                case WifiManager.RSSI_PKTCNT_FETCH_FAILED:
                     if (DBG) logd("RSSI_FETCH_FAILED");
                     break;
 
@@ -944,18 +942,18 @@
                     if (!mIsScreenOn) {
                         transitionTo(mOnlineState);
                     } else if (msg.arg1 == mRssiFetchToken) {
-                        mWsmChannel.sendMessage(RSSI_PKTCNT_FETCH, new RssiPktcntStat());
+                        mWsmChannel.sendMessage(WifiManager.RSSI_PKTCNT_FETCH);
                         sendMessageDelayed(obtainMessage(CMD_RSSI_FETCH, ++mRssiFetchToken, 0),
                                 LINK_SAMPLING_INTERVAL_MS);
                     }
                     break;
 
-                case RSSI_PKTCNT_FETCH_SUCCEEDED:
-                    RssiPktcntStat stat = (RssiPktcntStat) msg.obj;
-                    int rssi = stat.rssi;
+                case WifiManager.RSSI_PKTCNT_FETCH_SUCCEEDED:
+                    RssiPacketCountInfo info = (RssiPacketCountInfo) msg.obj;
+                    int rssi = info.rssi;
                     int mrssi = (mLastRssi + rssi) / 2;
-                    int txbad = stat.txbad;
-                    int txgood = stat.txgood;
+                    int txbad = info.txbad;
+                    int txgood = info.txgood;
                     if (DBG) logd("Fetch RSSI succeed, rssi=" + rssi + " mrssi=" + mrssi + " txbad="
                             + txbad + " txgood=" + txgood);
 
@@ -1003,7 +1001,7 @@
                     mLastRssi = rssi;
                     break;
 
-                case RSSI_PKTCNT_FETCH_FAILED:
+                case WifiManager.RSSI_PKTCNT_FETCH_FAILED:
                     // can happen if we are waiting to get a disconnect notification
                     if (DBG) logd("RSSI_FETCH_FAILED");
                     break;
@@ -1159,15 +1157,6 @@
     }
 
     /**
-     * Bundle of RSSI and packet count information
-     */
-    public class RssiPktcntStat {
-        public int rssi;
-        public int txgood;
-        public int txbad;
-    }
-
-    /**
      * Bundle of good link count parameters
      */
     private static class GoodLinkTarget {