Merge "Glop mesh reorg, support for drawBitmapMesh"
diff --git a/api/current.txt b/api/current.txt
index c0ad9c6..676a1cd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2019,6 +2019,7 @@
     field public static final int ThemeOverlay_Material_ActionBar = 16974409; // 0x1030249
     field public static final int ThemeOverlay_Material_Dark = 16974411; // 0x103024b
     field public static final int ThemeOverlay_Material_Dark_ActionBar = 16974412; // 0x103024c
+    field public static final int ThemeOverlay_Material_Dialog = 16974564; // 0x10302e4
     field public static final int ThemeOverlay_Material_Light = 16974410; // 0x103024a
     field public static final int Theme_Black = 16973832; // 0x1030008
     field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
@@ -3746,8 +3747,8 @@
 
   public class AlertDialog extends android.app.Dialog implements android.content.DialogInterface {
     ctor protected AlertDialog(android.content.Context);
-    ctor protected AlertDialog(android.content.Context, int);
     ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+    ctor protected AlertDialog(android.content.Context, int);
     method public android.widget.Button getButton(int);
     method public android.widget.ListView getListView();
     method public void setButton(int, java.lang.CharSequence, android.os.Message);
@@ -3766,11 +3767,11 @@
     method public void setMessage(java.lang.CharSequence);
     method public void setView(android.view.View);
     method public void setView(android.view.View, int, int, int, int);
-    field public static final int THEME_DEVICE_DEFAULT_DARK = 4; // 0x4
-    field public static final int THEME_DEVICE_DEFAULT_LIGHT = 5; // 0x5
-    field public static final int THEME_HOLO_DARK = 2; // 0x2
-    field public static final int THEME_HOLO_LIGHT = 3; // 0x3
-    field public static final int THEME_TRADITIONAL = 1; // 0x1
+    field public static final deprecated int THEME_DEVICE_DEFAULT_DARK = 4; // 0x4
+    field public static final deprecated int THEME_DEVICE_DEFAULT_LIGHT = 5; // 0x5
+    field public static final deprecated int THEME_HOLO_DARK = 2; // 0x2
+    field public static final deprecated int THEME_HOLO_LIGHT = 3; // 0x3
+    field public static final deprecated int THEME_TRADITIONAL = 1; // 0x1
   }
 
   public static class AlertDialog.Builder {
@@ -3785,7 +3786,7 @@
     method public android.app.AlertDialog.Builder setIcon(int);
     method public android.app.AlertDialog.Builder setIcon(android.graphics.drawable.Drawable);
     method public android.app.AlertDialog.Builder setIconAttribute(int);
-    method public android.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
+    method public deprecated android.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
     method public android.app.AlertDialog.Builder setItems(int, android.content.DialogInterface.OnClickListener);
     method public android.app.AlertDialog.Builder setItems(java.lang.CharSequence[], android.content.DialogInterface.OnClickListener);
     method public android.app.AlertDialog.Builder setMessage(int);
@@ -5478,7 +5479,6 @@
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
-    method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
     method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -5527,7 +5527,6 @@
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
-    method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
     method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
     method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
     method public void uninstallAllUserCaCerts(android.content.ComponentName);
@@ -7321,6 +7320,7 @@
     method public final java.lang.String getString(int);
     method public final java.lang.String getString(int, java.lang.Object...);
     method public abstract java.lang.Object getSystemService(java.lang.String);
+    method public final T getSystemService(java.lang.Class<T>);
     method public final java.lang.CharSequence getText(int);
     method public abstract android.content.res.Resources.Theme getTheme();
     method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
@@ -7450,7 +7450,7 @@
     method public int checkPermission(java.lang.String, int, int);
     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 deprecated void clearWallpaper() throws java.io.IOException;
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -7493,20 +7493,21 @@
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
     method public java.lang.Object getSystemService(java.lang.String);
+    method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
-    method public android.graphics.drawable.Drawable getWallpaper();
-    method public int getWallpaperDesiredMinimumHeight();
-    method public int getWallpaperDesiredMinimumWidth();
+    method public deprecated android.graphics.drawable.Drawable getWallpaper();
+    method public deprecated int getWallpaperDesiredMinimumHeight();
+    method public deprecated int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
-    method public android.graphics.drawable.Drawable peekWallpaper();
+    method public deprecated android.graphics.drawable.Drawable peekWallpaper();
     method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
     method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
-    method public void removeStickyBroadcast(android.content.Intent);
-    method public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+    method public deprecated void removeStickyBroadcast(android.content.Intent);
+    method public deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     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);
@@ -7515,13 +7516,13 @@
     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 sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void sendStickyBroadcast(android.content.Intent);
-    method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
-    method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public deprecated void sendStickyBroadcast(android.content.Intent);
+    method public deprecated void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+    method public deprecated void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public deprecated void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void setTheme(int);
-    method public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
-    method public void setWallpaper(java.io.InputStream) throws java.io.IOException;
+    method public deprecated void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
+    method public deprecated void setWallpaper(java.io.InputStream) throws java.io.IOException;
     method public void startActivities(android.content.Intent[]);
     method public void startActivities(android.content.Intent[], android.os.Bundle);
     method public void startActivity(android.content.Intent);
@@ -21781,7 +21782,6 @@
   }
 
   public class BatteryManager {
-    ctor public BatteryManager();
     method public int getIntProperty(int);
     method public long getLongProperty(int);
     field public static final int BATTERY_HEALTH_COLD = 7; // 0x7
@@ -27657,7 +27657,7 @@
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onReady();
     method public void onShutdown();
-    method public void startSession(android.os.Bundle, int);
+    method public void showSession(android.os.Bundle, int);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
     field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
     field public static final int START_WITH_ASSIST = 1; // 0x1
@@ -27669,6 +27669,7 @@
     method public void finish();
     method public android.view.LayoutInflater getLayoutInflater();
     method public android.app.Dialog getWindow();
+    method public void hide();
     method public void hideWindow();
     method public void onAbortVoice(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
     method public void onBackPressed();
@@ -27683,14 +27684,17 @@
     method public void onDestroy();
     method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
     method public void onHandleAssist(android.os.Bundle);
+    method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
     method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public void onShow(android.os.Bundle, int);
     method public void onTaskFinished(android.content.Intent, int);
     method public void onTaskStarted(android.content.Intent, int);
     method public void setContentView(android.view.View);
     method public void setTheme(int);
+    method public void show();
     method public void showWindow();
     method public void startVoiceActivity(android.content.Intent);
   }
@@ -29844,6 +29848,7 @@
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
     method public java.lang.Object getSystemService(java.lang.String);
+    method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
     method public android.graphics.drawable.Drawable getWallpaper();
     method public int getWallpaperDesiredMinimumHeight();
diff --git a/api/removed.txt b/api/removed.txt
index 9322973..8668a77 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -16,6 +16,10 @@
 
 package android.os {
 
+  public class BatteryManager {
+    ctor public BatteryManager();
+  }
+
   public final class PowerManager {
     method public void goToSleep(long);
     method public deprecated void userActivity(long, boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index deaa5f0..95e57c4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2097,6 +2097,7 @@
     field public static final int ThemeOverlay_Material_ActionBar = 16974409; // 0x1030249
     field public static final int ThemeOverlay_Material_Dark = 16974411; // 0x103024b
     field public static final int ThemeOverlay_Material_Dark_ActionBar = 16974412; // 0x103024c
+    field public static final int ThemeOverlay_Material_Dialog = 16974564; // 0x10302e4
     field public static final int ThemeOverlay_Material_Light = 16974410; // 0x103024a
     field public static final int Theme_Black = 16973832; // 0x1030008
     field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
@@ -3835,8 +3836,8 @@
 
   public class AlertDialog extends android.app.Dialog implements android.content.DialogInterface {
     ctor protected AlertDialog(android.content.Context);
-    ctor protected AlertDialog(android.content.Context, int);
     ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
+    ctor protected AlertDialog(android.content.Context, int);
     method public android.widget.Button getButton(int);
     method public android.widget.ListView getListView();
     method public void setButton(int, java.lang.CharSequence, android.os.Message);
@@ -3855,11 +3856,11 @@
     method public void setMessage(java.lang.CharSequence);
     method public void setView(android.view.View);
     method public void setView(android.view.View, int, int, int, int);
-    field public static final int THEME_DEVICE_DEFAULT_DARK = 4; // 0x4
-    field public static final int THEME_DEVICE_DEFAULT_LIGHT = 5; // 0x5
-    field public static final int THEME_HOLO_DARK = 2; // 0x2
-    field public static final int THEME_HOLO_LIGHT = 3; // 0x3
-    field public static final int THEME_TRADITIONAL = 1; // 0x1
+    field public static final deprecated int THEME_DEVICE_DEFAULT_DARK = 4; // 0x4
+    field public static final deprecated int THEME_DEVICE_DEFAULT_LIGHT = 5; // 0x5
+    field public static final deprecated int THEME_HOLO_DARK = 2; // 0x2
+    field public static final deprecated int THEME_HOLO_LIGHT = 3; // 0x3
+    field public static final deprecated int THEME_TRADITIONAL = 1; // 0x1
   }
 
   public static class AlertDialog.Builder {
@@ -3874,7 +3875,7 @@
     method public android.app.AlertDialog.Builder setIcon(int);
     method public android.app.AlertDialog.Builder setIcon(android.graphics.drawable.Drawable);
     method public android.app.AlertDialog.Builder setIconAttribute(int);
-    method public android.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
+    method public deprecated android.app.AlertDialog.Builder setInverseBackgroundForced(boolean);
     method public android.app.AlertDialog.Builder setItems(int, android.content.DialogInterface.OnClickListener);
     method public android.app.AlertDialog.Builder setItems(java.lang.CharSequence[], android.content.DialogInterface.OnClickListener);
     method public android.app.AlertDialog.Builder setMessage(int);
@@ -5578,7 +5579,6 @@
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
-    method public java.util.List<android.os.PersistableBundle> getTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName);
     method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
     method public boolean hasGrantedPolicy(android.content.ComponentName, int);
     method public boolean installCaCert(android.content.ComponentName, byte[]);
@@ -5628,7 +5628,6 @@
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
-    method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
     method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
     method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
     method public void uninstallAllUserCaCerts(android.content.ComponentName);
@@ -7526,6 +7525,7 @@
     method public final java.lang.String getString(int);
     method public final java.lang.String getString(int, java.lang.Object...);
     method public abstract java.lang.Object getSystemService(java.lang.String);
+    method public final T getSystemService(java.lang.Class<T>);
     method public final java.lang.CharSequence getText(int);
     method public abstract android.content.res.Resources.Theme getTheme();
     method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
@@ -7661,7 +7661,7 @@
     method public int checkPermission(java.lang.String, int, int);
     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 deprecated void clearWallpaper() throws java.io.IOException;
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -7704,20 +7704,21 @@
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
     method public java.lang.Object getSystemService(java.lang.String);
+    method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
-    method public android.graphics.drawable.Drawable getWallpaper();
-    method public int getWallpaperDesiredMinimumHeight();
-    method public int getWallpaperDesiredMinimumWidth();
+    method public deprecated android.graphics.drawable.Drawable getWallpaper();
+    method public deprecated int getWallpaperDesiredMinimumHeight();
+    method public deprecated int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
-    method public android.graphics.drawable.Drawable peekWallpaper();
+    method public deprecated android.graphics.drawable.Drawable peekWallpaper();
     method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
     method public android.content.Intent registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter, java.lang.String, android.os.Handler);
-    method public void removeStickyBroadcast(android.content.Intent);
-    method public void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+    method public deprecated void removeStickyBroadcast(android.content.Intent);
+    method public deprecated void removeStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
     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);
@@ -7726,13 +7727,13 @@
     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 sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void sendStickyBroadcast(android.content.Intent);
-    method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
-    method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
-    method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public deprecated void sendStickyBroadcast(android.content.Intent);
+    method public deprecated void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle);
+    method public deprecated void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
+    method public deprecated void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle);
     method public void setTheme(int);
-    method public void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
-    method public void setWallpaper(java.io.InputStream) throws java.io.IOException;
+    method public deprecated void setWallpaper(android.graphics.Bitmap) throws java.io.IOException;
+    method public deprecated void setWallpaper(java.io.InputStream) throws java.io.IOException;
     method public void startActivities(android.content.Intent[]);
     method public void startActivities(android.content.Intent[], android.os.Bundle);
     method public void startActivity(android.content.Intent);
@@ -23370,7 +23371,6 @@
   }
 
   public class BatteryManager {
-    ctor public BatteryManager();
     method public int getIntProperty(int);
     method public long getLongProperty(int);
     field public static final int BATTERY_HEALTH_COLD = 7; // 0x7
@@ -29346,7 +29346,7 @@
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onReady();
     method public void onShutdown();
-    method public void startSession(android.os.Bundle, int);
+    method public void showSession(android.os.Bundle, int);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
     field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
     field public static final int START_WITH_ASSIST = 1; // 0x1
@@ -29358,6 +29358,7 @@
     method public void finish();
     method public android.view.LayoutInflater getLayoutInflater();
     method public android.app.Dialog getWindow();
+    method public void hide();
     method public void hideWindow();
     method public void onAbortVoice(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
     method public void onBackPressed();
@@ -29372,14 +29373,17 @@
     method public void onDestroy();
     method public boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
     method public void onHandleAssist(android.os.Bundle);
+    method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
     method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public void onShow(android.os.Bundle, int);
     method public void onTaskFinished(android.content.Intent, int);
     method public void onTaskStarted(android.content.Intent, int);
     method public void setContentView(android.view.View);
     method public void setTheme(int);
+    method public void show();
     method public void showWindow();
     method public void startVoiceActivity(android.content.Intent);
   }
@@ -32005,6 +32009,7 @@
     method public android.content.res.Resources getResources();
     method public android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
     method public java.lang.Object getSystemService(java.lang.String);
+    method public java.lang.String getSystemServiceName(java.lang.Class<?>);
     method public android.content.res.Resources.Theme getTheme();
     method public android.graphics.drawable.Drawable getWallpaper();
     method public int getWallpaperDesiredMinimumHeight();
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 9322973..8668a77 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -16,6 +16,10 @@
 
 package android.os {
 
+  public class BatteryManager {
+    ctor public BatteryManager();
+  }
+
   public final class PowerManager {
     method public void goToSleep(long);
     method public deprecated void userActivity(long, boolean);
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index e3b27b5..2939322 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -206,7 +206,6 @@
     private ArrayList<GhostViewListeners> mGhostViewListeners =
             new ArrayList<GhostViewListeners>();
     private ArrayMap<View, Float> mOriginalAlphas = new ArrayMap<View, Float>();
-    final private ArrayList<View> mRootSharedElements = new ArrayList<View>();
     private ArrayList<Matrix> mSharedElementParentMatrices;
 
     public ActivityTransitionCoordinator(Window window,
@@ -253,17 +252,10 @@
                 final String name = sharedElements.keyAt(i);
                 if (isFirstRun && (view == null || !view.isAttachedToWindow() || name == null)) {
                     sharedElements.removeAt(i);
-                } else {
-                    if (!isNested(view, sharedElements)) {
-                        mSharedElementNames.add(name);
-                        mSharedElements.add(view);
-                        sharedElements.removeAt(i);
-                        if (isFirstRun) {
-                            // We need to keep track which shared elements are roots
-                            // and which are nested.
-                            mRootSharedElements.add(view);
-                        }
-                    }
+                } else if (!isNested(view, sharedElements)) {
+                    mSharedElementNames.add(name);
+                    mSharedElements.add(view);
+                    sharedElements.removeAt(i);
                 }
             }
             isFirstRun = false;
@@ -520,24 +512,9 @@
     }
 
     private void getSharedElementParentMatrix(View view, Matrix matrix) {
-        final boolean isNestedInOtherSharedElement = !mRootSharedElements.contains(view);
-        final boolean useParentMatrix;
-        if (isNestedInOtherSharedElement) {
-            useParentMatrix = true;
-        } else {
-            final int index = mSharedElementParentMatrices == null ? -1
-                    : mSharedElements.indexOf(view);
-            if (index < 0) {
-                useParentMatrix = true;
-            } else {
-                // The indices of mSharedElementParentMatrices matches the
-                // mSharedElement matrices.
-                Matrix parentMatrix = mSharedElementParentMatrices.get(index);
-                matrix.set(parentMatrix);
-                useParentMatrix = false;
-            }
-        }
-        if (useParentMatrix) {
+        final int index = mSharedElementParentMatrices == null ? -1
+                : mSharedElements.indexOf(view);
+        if (index < 0) {
             matrix.reset();
             ViewParent viewParent = view.getParent();
             if (viewParent instanceof ViewGroup) {
@@ -545,6 +522,11 @@
                 ViewGroup parent = (ViewGroup) viewParent;
                 parent.transformMatrixToLocal(matrix);
             }
+        } else {
+            // The indices of mSharedElementParentMatrices matches the
+            // mSharedElement matrices.
+            Matrix parentMatrix = mSharedElementParentMatrices.get(index);
+            matrix.set(parentMatrix);
         }
     }
 
@@ -701,7 +683,6 @@
         mResultReceiver = null;
         mPendingTransition = null;
         mListener = null;
-        mRootSharedElements.clear();
         mSharedElementParentMatrices = null;
     }
 
@@ -817,9 +798,12 @@
         ViewGroup decor = getDecor();
         if (decor != null) {
             boolean moveWithParent = moveSharedElementWithParent();
+            Matrix tempMatrix = new Matrix();
             for (int i = 0; i < numSharedElements; i++) {
                 View view = mSharedElements.get(i);
-                GhostView.addGhost(view, decor);
+                tempMatrix.reset();
+                mSharedElementParentMatrices.get(i).invert(tempMatrix);
+                GhostView.addGhost(view, decor, tempMatrix);
                 ViewGroup parent = (ViewGroup) view.getParent();
                 if (moveWithParent && !isInTransitionGroup(parent, decor)) {
                     GhostViewListeners listener = new GhostViewListeners(view, parent, decor);
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index c8f58c6..3e545f9 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -38,6 +38,8 @@
 import android.widget.ListAdapter;
 import android.widget.ListView;
 
+import com.android.internal.R;
+
 /**
  * A subclass of Dialog that can display one, two or three buttons. If you only want to
  * display a String in this dialog box, use the setMessage() method.  If you
@@ -48,7 +50,7 @@
  * FrameLayout fl = (FrameLayout) findViewById(android.R.id.custom);
  * fl.addView(myView, new LayoutParams(MATCH_PARENT, WRAP_CONTENT));
  * </pre>
- * 
+ *
  * <p>The AlertDialog class takes care of automatically setting
  * {@link WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM
  * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM} for you based on whether
@@ -70,31 +72,46 @@
     /**
      * Special theme constant for {@link #AlertDialog(Context, int)}: use
      * the traditional (pre-Holo) alert dialog theme.
+     *
+     * @deprecated Use {@link android.R.style#Theme_Material_Dialog_Alert}.
      */
+    @Deprecated
     public static final int THEME_TRADITIONAL = 1;
-    
+
     /**
      * Special theme constant for {@link #AlertDialog(Context, int)}: use
      * the holographic alert theme with a dark background.
+     *
+     * @deprecated Use {@link android.R.style#Theme_Material_Dialog_Alert}.
      */
+    @Deprecated
     public static final int THEME_HOLO_DARK = 2;
-    
+
     /**
      * Special theme constant for {@link #AlertDialog(Context, int)}: use
      * the holographic alert theme with a light background.
+     *
+     * @deprecated Use {@link android.R.style#Theme_Material_Light_Dialog_Alert}.
      */
+    @Deprecated
     public static final int THEME_HOLO_LIGHT = 3;
 
     /**
      * Special theme constant for {@link #AlertDialog(Context, int)}: use
      * the device's default alert theme with a dark background.
+     *
+     * @deprecated Use {@link android.R.style#Theme_DeviceDefault_Dialog_Alert}.
      */
+    @Deprecated
     public static final int THEME_DEVICE_DEFAULT_DARK = 4;
 
     /**
      * Special theme constant for {@link #AlertDialog(Context, int)}: use
      * the device's default alert theme with a light background.
+     *
+     * @deprecated Use {@link android.R.style#Theme_DeviceDefault_Light_Dialog_Alert}.
      */
+    @Deprecated
     public static final int THEME_DEVICE_DEFAULT_LIGHT = 5;
 
     /**
@@ -108,55 +125,92 @@
      * @hide
      */
     public static final int LAYOUT_HINT_SIDE = 1;
-    
+
+    /**
+     * Creates an alert dialog that uses the default alert dialog theme.
+     * <p>
+     * The default alert dialog theme is defined by
+     * {@link android.R.attr#alertDialogTheme} within the parent
+     * {@code context}'s theme.
+     *
+     * @param context the parent context
+     */
     protected AlertDialog(Context context) {
-        this(context, resolveDialogTheme(context, 0), true);
+        this(context, 0);
     }
 
     /**
-     * Construct an AlertDialog that uses an explicit theme.  The actual style
-     * that an AlertDialog uses is a private implementation, however you can
-     * here supply either the name of an attribute in the theme from which
-     * to get the dialog's style (such as {@link android.R.attr#alertDialogTheme}
-     * or one of the constants {@link #THEME_TRADITIONAL},
-     * {@link #THEME_HOLO_DARK}, or {@link #THEME_HOLO_LIGHT}.
+     * Creates an alert dialog that uses the default alert dialog theme and a
+     * custom cancel listener.
+     * <p>
+     * This is functionally identical to:
+     * <pre>
+     *     AlertDialog dialog = new AlertDialog(context);
+     *     alertDialog.setCancelable(cancelable);
+     *     alertDialog.setOnCancelListener(cancelListener);
+     * </pre>
+     * <p>
+     * The default alert dialog theme is defined by
+     * {@link android.R.attr#alertDialogTheme} within the parent
+     * {@code context}'s theme.
+     *
+     * @param context the parent context
      */
-    protected AlertDialog(Context context, @AttrRes int theme) {
-        this(context, theme, true);
+    protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
+        this(context, 0);
+
+        setCancelable(cancelable);
+        setOnCancelListener(cancelListener);
     }
 
-    AlertDialog(Context context, int theme, boolean createThemeContextWrapper) {
-        super(context, resolveDialogTheme(context, theme), createThemeContextWrapper);
+    /**
+     * Creates an alert dialog that uses an explicit theme resource.
+     * <p>
+     * The specified theme resource ({@code themeResId}) is applied on top of
+     * the parent {@code context}'s theme. It may be specified as a style
+     * resource containing a fully-populated theme, such as
+     * {@link android.R.style#Theme_Material_Dialog}, to replace all attributes
+     * in the parent {@code context}'s theme including primary and accent
+     * colors.
+     * <p>
+     * To preserve attributes such as primary and accent colors, the
+     * {@code themeResId} may instead be specified as an overlay theme such as
+     * {@link android.R.style#ThemeOverlay_Material_Dialog}. This will override
+     * only the window attributes necessary to style the alert window as a
+     * dialog.
+     * <p>
+     * Alternatively, the {@code themeResId} may be specified as {@code 0} to
+     * use the parent {@code context}'s resolved value for
+     * {@link android.R.attr#alertDialogTheme}.
+     *
+     * @param context the parent context
+     * @param themeResId the resource ID of the theme against which to inflate
+     *                   this dialog, or {@code 0} to use the parent
+     *                   {@code context}'s default alert dialog theme
+     */
+    protected AlertDialog(Context context, @AttrRes int themeResId) {
+        super(context, resolveDialogTheme(context, themeResId));
 
         mWindow.alwaysReadCloseOnTouchAttr();
         mAlert = new AlertController(getContext(), this, getWindow());
     }
 
-    protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
-        super(context, resolveDialogTheme(context, 0));
-        mWindow.alwaysReadCloseOnTouchAttr();
-        setCancelable(cancelable);
-        setOnCancelListener(cancelListener);
-        mAlert = new AlertController(context, this, getWindow());
-    }
-
-    static int resolveDialogTheme(Context context, int resid) {
-        if (resid == THEME_TRADITIONAL) {
-            return com.android.internal.R.style.Theme_Dialog_Alert;
-        } else if (resid == THEME_HOLO_DARK) {
-            return com.android.internal.R.style.Theme_Holo_Dialog_Alert;
-        } else if (resid == THEME_HOLO_LIGHT) {
-            return com.android.internal.R.style.Theme_Holo_Light_Dialog_Alert;
-        } else if (resid == THEME_DEVICE_DEFAULT_DARK) {
-            return com.android.internal.R.style.Theme_DeviceDefault_Dialog_Alert;
-        } else if (resid == THEME_DEVICE_DEFAULT_LIGHT) {
-            return com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog_Alert;
-        } else if (resid >= 0x01000000) {   // start of real resource IDs.
-            return resid;
+    static int resolveDialogTheme(Context context, int themeResId) {
+        if (themeResId == THEME_TRADITIONAL) {
+            return R.style.Theme_Dialog_Alert;
+        } else if (themeResId == THEME_HOLO_DARK) {
+            return R.style.Theme_Holo_Dialog_Alert;
+        } else if (themeResId == THEME_HOLO_LIGHT) {
+            return R.style.Theme_Holo_Light_Dialog_Alert;
+        } else if (themeResId == THEME_DEVICE_DEFAULT_DARK) {
+            return R.style.Theme_DeviceDefault_Dialog_Alert;
+        } else if (themeResId == THEME_DEVICE_DEFAULT_LIGHT) {
+            return R.style.Theme_DeviceDefault_Light_Dialog_Alert;
+        } else if (themeResId >= 0x01000000) {   // start of real resource IDs.
+            return themeResId;
         } else {
-            TypedValue outValue = new TypedValue();
-            context.getTheme().resolveAttribute(com.android.internal.R.attr.alertDialogTheme,
-                    outValue, true);
+            final TypedValue outValue = new TypedValue();
+            context.getTheme().resolveAttribute(R.attr.alertDialogTheme, outValue, true);
             return outValue.resourceId;
         }
     }
@@ -177,13 +231,13 @@
 
     /**
      * Gets the list view used in the dialog.
-     *  
+     *
      * @return The {@link ListView} from the dialog.
      */
     public ListView getListView() {
         return mAlert.getListView();
     }
-    
+
     @Override
     public void setTitle(CharSequence title) {
         super.setTitle(title);
@@ -196,7 +250,7 @@
     public void setCustomTitle(View customTitleView) {
         mAlert.setCustomTitle(customTitleView);
     }
-    
+
     public void setMessage(CharSequence message) {
         mAlert.setMessage(message);
     }
@@ -207,9 +261,9 @@
     public void setView(View view) {
         mAlert.setView(view);
     }
-    
+
     /**
-     * Set the view to display in that dialog, specifying the spacing to appear around that 
+     * Set the view to display in that dialog, specifying the spacing to appear around that
      * view.
      *
      * @param view The view to show in the content area of the dialog
@@ -233,7 +287,7 @@
 
     /**
      * Set a message to be sent when a button is pressed.
-     * 
+     *
      * @param whichButton Which button to set the message for, can be one of
      *            {@link DialogInterface#BUTTON_POSITIVE},
      *            {@link DialogInterface#BUTTON_NEGATIVE}, or
@@ -244,10 +298,10 @@
     public void setButton(int whichButton, CharSequence text, Message msg) {
         mAlert.setButton(whichButton, text, null, msg);
     }
-    
+
     /**
      * Set a listener to be invoked when the positive button of the dialog is pressed.
-     * 
+     *
      * @param whichButton Which button to set the listener on, can be one of
      *            {@link DialogInterface#BUTTON_POSITIVE},
      *            {@link DialogInterface#BUTTON_NEGATIVE}, or
@@ -267,7 +321,7 @@
     public void setButton(CharSequence text, Message msg) {
         setButton(BUTTON_POSITIVE, text, msg);
     }
-        
+
     /**
      * @deprecated Use {@link #setButton(int, CharSequence, Message)} with
      *             {@link DialogInterface#BUTTON_NEGATIVE}.
@@ -288,7 +342,7 @@
 
     /**
      * Set a listener to be invoked when button 1 of the dialog is pressed.
-     * 
+     *
      * @param text The text to display in button 1.
      * @param listener The {@link DialogInterface.OnClickListener} to use.
      * @deprecated Use
@@ -334,7 +388,7 @@
     public void setIcon(@DrawableRes int resId) {
         mAlert.setIcon(resId);
     }
-    
+
     public void setIcon(Drawable icon) {
         mAlert.setIcon(icon);
     }
@@ -353,7 +407,7 @@
     public void setInverseBackgroundForced(boolean forceInverseBackground) {
         mAlert.setInverseBackgroundForced(forceInverseBackground);
     }
-    
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -371,35 +425,57 @@
         if (mAlert.onKeyUp(keyCode, event)) return true;
         return super.onKeyUp(keyCode, event);
     }
-    
+
     public static class Builder {
         private final AlertController.AlertParams P;
-        private int mTheme;
-        
+        private int mThemeResId;
+
         /**
-         * Constructor using a context for this builder and the {@link AlertDialog} it creates.
+         * Creates a builder for an alert dialog that uses the default alert
+         * dialog theme.
+         * <p>
+         * The default alert dialog theme is defined by
+         * {@link android.R.attr#alertDialogTheme} within the parent
+         * {@code context}'s theme.
+         *
+         * @param context the parent context
          */
         public Builder(Context context) {
             this(context, resolveDialogTheme(context, 0));
         }
 
         /**
-         * Constructor using a context and theme for this builder and
-         * the {@link AlertDialog} it creates.  The actual theme
-         * that an AlertDialog uses is a private implementation, however you can
-         * here supply either the name of an attribute in the theme from which
-         * to get the dialog's style (such as {@link android.R.attr#alertDialogTheme}
-         * or one of the constants
-         * {@link AlertDialog#THEME_TRADITIONAL AlertDialog.THEME_TRADITIONAL},
-         * {@link AlertDialog#THEME_HOLO_DARK AlertDialog.THEME_HOLO_DARK}, or
-         * {@link AlertDialog#THEME_HOLO_LIGHT AlertDialog.THEME_HOLO_LIGHT}.
+         * Creates a builder for an alert dialog that uses an explicit theme
+         * resource.
+         * <p>
+         * The specified theme resource ({@code themeResId}) is applied on top
+         * of the parent {@code context}'s theme. It may be specified as a
+         * style resource containing a fully-populated theme, such as
+         * {@link android.R.style#Theme_Material_Dialog}, to replace all
+         * attributes in the parent {@code context}'s theme including primary
+         * and accent colors.
+         * <p>
+         * To preserve attributes such as primary and accent colors, the
+         * {@code themeResId} may instead be specified as an overlay theme such
+         * as {@link android.R.style#ThemeOverlay_Material_Dialog}. This will
+         * override only the window attributes necessary to style the alert
+         * window as a dialog.
+         * <p>
+         * Alternatively, the {@code themeResId} may be specified as {@code 0}
+         * to use the parent {@code context}'s resolved value for
+         * {@link android.R.attr#alertDialogTheme}.
+         *
+         * @param context the parent context
+         * @param themeResId the resource ID of the theme against which to inflate
+         *                   this dialog, or {@code 0} to use the parent
+         *                   {@code context}'s default alert dialog theme
          */
-        public Builder(Context context, int theme) {
+        public Builder(Context context, int themeResId) {
             P = new AlertController.AlertParams(new ContextThemeWrapper(
-                    context, resolveDialogTheme(context, theme)));
-            mTheme = theme;
+                    context, resolveDialogTheme(context, themeResId)));
+            mThemeResId = themeResId;
         }
-        
+
         /**
          * Returns a {@link Context} with the appropriate theme for dialogs created by this Builder.
          * Applications should use this Context for obtaining LayoutInflaters for inflating views
@@ -421,7 +497,7 @@
             P.mTitle = P.mContext.getText(titleId);
             return this;
         }
-        
+
         /**
          * Set the title displayed in the {@link Dialog}.
          *
@@ -431,23 +507,28 @@
             P.mTitle = title;
             return this;
         }
-        
+
         /**
-         * Set the title using the custom view {@code customTitleView}. The
-         * methods {@link #setTitle(int)} and {@link #setIcon(int)} should be
-         * sufficient for most titles, but this is provided if the title needs
-         * more customization. Using this will replace the title and icon set
-         * via the other methods.
-         * 
-         * @param customTitleView The custom view to use as the title.
+         * Set the title using the custom view {@code customTitleView}.
+         * <p>
+         * The methods {@link #setTitle(int)} and {@link #setIcon(int)} should
+         * be sufficient for most titles, but this is provided if the title
+         * needs more customization. Using this will replace the title and icon
+         * set via the other methods.
+         * <p>
+         * <strong>Note:</strong> To ensure consistent styling, the custom view
+         * should be inflated or constructed using the alert dialog's themed
+         * context obtained via {@link #getContext()}.
          *
-         * @return This Builder object to allow for chaining of calls to set methods
+         * @param customTitleView the custom view to use as the title
+         * @return this Builder object to allow for chaining of calls to set
+         *         methods
          */
         public Builder setCustomTitle(View customTitleView) {
             P.mCustomTitleView = customTitleView;
             return this;
         }
-        
+
         /**
          * Set the message to display using the given resource id.
          *
@@ -457,7 +538,7 @@
             P.mMessage = P.mContext.getText(messageId);
             return this;
         }
-        
+
         /**
          * Set the message to display.
           *
@@ -467,7 +548,7 @@
             P.mMessage = message;
             return this;
         }
-        
+
         /**
          * Set the resource id of the {@link Drawable} to be used in the title.
          * <p>
@@ -479,11 +560,16 @@
             P.mIconId = iconId;
             return this;
         }
-        
+
         /**
          * Set the {@link Drawable} to be used in the title.
-          *
-         * @return This Builder object to allow for chaining of calls to set methods
+         * <p>
+         * <strong>Note:</strong> To ensure consistent styling, the drawable
+         * should be inflated or constructed using the alert dialog's themed
+         * context obtained via {@link #getContext()}.
+         *
+         * @return this Builder object to allow for chaining of calls to set
+         *         methods
          */
         public Builder setIcon(Drawable icon) {
             P.mIcon = icon;
@@ -518,7 +604,7 @@
             P.mPositiveButtonListener = listener;
             return this;
         }
-        
+
         /**
          * Set a listener to be invoked when the positive button of the dialog is pressed.
          * @param text The text to display in the positive button
@@ -531,7 +617,7 @@
             P.mPositiveButtonListener = listener;
             return this;
         }
-        
+
         /**
          * Set a listener to be invoked when the negative button of the dialog is pressed.
          * @param textId The resource id of the text to display in the negative button
@@ -544,7 +630,7 @@
             P.mNegativeButtonListener = listener;
             return this;
         }
-        
+
         /**
          * Set a listener to be invoked when the negative button of the dialog is pressed.
          * @param text The text to display in the negative button
@@ -557,7 +643,7 @@
             P.mNegativeButtonListener = listener;
             return this;
         }
-        
+
         /**
          * Set a listener to be invoked when the neutral button of the dialog is pressed.
          * @param textId The resource id of the text to display in the neutral button
@@ -570,7 +656,7 @@
             P.mNeutralButtonListener = listener;
             return this;
         }
-        
+
         /**
          * Set a listener to be invoked when the neutral button of the dialog is pressed.
          * @param text The text to display in the neutral button
@@ -583,7 +669,7 @@
             P.mNeutralButtonListener = listener;
             return this;
         }
-        
+
         /**
          * Sets whether the dialog is cancelable or not.  Default is true.
          *
@@ -593,7 +679,7 @@
             P.mCancelable = cancelable;
             return this;
         }
-        
+
         /**
          * Sets the callback that will be called if the dialog is canceled.
          *
@@ -611,7 +697,7 @@
             P.mOnCancelListener = onCancelListener;
             return this;
         }
-        
+
         /**
          * Sets the callback that will be called when the dialog is dismissed for any reason.
          *
@@ -631,7 +717,7 @@
             P.mOnKeyListener = onKeyListener;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content, you will be notified of the
          * selected item via the supplied listener. This should be an array type i.e. R.array.foo
@@ -643,7 +729,7 @@
             P.mOnClickListener = listener;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content, you will be notified of the
          * selected item via the supplied listener.
@@ -655,12 +741,12 @@
             P.mOnClickListener = listener;
             return this;
         }
-        
+
         /**
          * Set a list of items, which are supplied by the given {@link ListAdapter}, to be
          * displayed in the dialog as the content, you will be notified of the
          * selected item via the supplied listener.
-         * 
+         *
          * @param adapter The {@link ListAdapter} to supply the list of items
          * @param listener The listener that will be called when an item is clicked.
          *
@@ -671,12 +757,12 @@
             P.mOnClickListener = listener;
             return this;
         }
-        
+
         /**
          * Set a list of items, which are supplied by the given {@link Cursor}, to be
          * displayed in the dialog as the content, you will be notified of the
          * selected item via the supplied listener.
-         * 
+         *
          * @param cursor The {@link Cursor} to supply the list of items
          * @param listener The listener that will be called when an item is clicked.
          * @param labelColumn The column name on the cursor containing the string to display
@@ -691,7 +777,7 @@
             P.mOnClickListener = listener;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content,
          * you will be notified of the selected item via the supplied listener.
@@ -699,7 +785,7 @@
          * a check mark displayed to the right of the text for each checked
          * item. Clicking on an item in the list will not dismiss the dialog.
          * Clicking on a button will dismiss the dialog.
-         * 
+         *
          * @param itemsId the resource id of an array i.e. R.array.foo
          * @param checkedItems specifies which items are checked. It should be null in which case no
          *        items are checked. If non null it must be exactly the same length as the array of
@@ -718,14 +804,14 @@
             P.mIsMultiChoice = true;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content,
          * you will be notified of the selected item via the supplied listener.
          * The list will have a check mark displayed to the right of the text
          * for each checked item. Clicking on an item in the list will not
          * dismiss the dialog. Clicking on a button will dismiss the dialog.
-         * 
+         *
          * @param items the text of the items to be displayed in the list.
          * @param checkedItems specifies which items are checked. It should be null in which case no
          *        items are checked. If non null it must be exactly the same length as the array of
@@ -736,7 +822,7 @@
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems, 
+        public Builder setMultiChoiceItems(CharSequence[] items, boolean[] checkedItems,
                 final OnMultiChoiceClickListener listener) {
             P.mItems = items;
             P.mOnCheckboxClickListener = listener;
@@ -744,14 +830,14 @@
             P.mIsMultiChoice = true;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content,
          * you will be notified of the selected item via the supplied listener.
          * The list will have a check mark displayed to the right of the text
          * for each checked item. Clicking on an item in the list will not
          * dismiss the dialog. Clicking on a button will dismiss the dialog.
-         * 
+         *
          * @param cursor the cursor used to provide the items.
          * @param isCheckedColumn specifies the column name on the cursor to use to determine
          *        whether a checkbox is checked or not. It must return an integer value where 1
@@ -764,7 +850,7 @@
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn, 
+        public Builder setMultiChoiceItems(Cursor cursor, String isCheckedColumn, String labelColumn,
                 final OnMultiChoiceClickListener listener) {
             P.mCursor = cursor;
             P.mOnCheckboxClickListener = listener;
@@ -773,14 +859,14 @@
             P.mIsMultiChoice = true;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content, you will be notified of
          * the selected item via the supplied listener. This should be an array type i.e.
          * R.array.foo The list will have a check mark displayed to the right of the text for the
          * checked item. Clicking on an item in the list will not dismiss the dialog. Clicking on a
          * button will dismiss the dialog.
-         * 
+         *
          * @param itemsId the resource id of an array i.e. R.array.foo
          * @param checkedItem specifies which item is checked. If -1 no items are checked.
          * @param listener notified when an item on the list is clicked. The dialog will not be
@@ -797,13 +883,13 @@
             P.mIsSingleChoice = true;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content, you will be notified of
          * the selected item via the supplied listener. The list will have a check mark displayed to
          * the right of the text for the checked item. Clicking on an item in the list will not
          * dismiss the dialog. Clicking on a button will dismiss the dialog.
-         * 
+         *
          * @param cursor the cursor to retrieve the items from.
          * @param checkedItem specifies which item is checked. If -1 no items are checked.
          * @param labelColumn The column name on the cursor containing the string to display in the
@@ -814,7 +900,7 @@
          *
          * @return This Builder object to allow for chaining of calls to set methods
          */
-        public Builder setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn, 
+        public Builder setSingleChoiceItems(Cursor cursor, int checkedItem, String labelColumn,
                 final OnClickListener listener) {
             P.mCursor = cursor;
             P.mOnClickListener = listener;
@@ -823,13 +909,13 @@
             P.mIsSingleChoice = true;
             return this;
         }
-        
+
         /**
          * Set a list of items to be displayed in the dialog as the content, you will be notified of
          * the selected item via the supplied listener. The list will have a check mark displayed to
          * the right of the text for the checked item. Clicking on an item in the list will not
          * dismiss the dialog. Clicking on a button will dismiss the dialog.
-         * 
+         *
          * @param items the items to be displayed.
          * @param checkedItem specifies which item is checked. If -1 no items are checked.
          * @param listener notified when an item on the list is clicked. The dialog will not be
@@ -844,14 +930,14 @@
             P.mCheckedItem = checkedItem;
             P.mIsSingleChoice = true;
             return this;
-        } 
-        
+        }
+
         /**
          * Set a list of items to be displayed in the dialog as the content, you will be notified of
          * the selected item via the supplied listener. The list will have a check mark displayed to
          * the right of the text for the checked item. Clicking on an item in the list will not
          * dismiss the dialog. Clicking on a button will dismiss the dialog.
-         * 
+         *
          * @param adapter The {@link ListAdapter} to supply the list of items
          * @param checkedItem specifies which item is checked. If -1 no items are checked.
          * @param listener notified when an item on the list is clicked. The dialog will not be
@@ -867,26 +953,25 @@
             P.mIsSingleChoice = true;
             return this;
         }
-        
+
         /**
          * Sets a listener to be invoked when an item in the list is selected.
-         * 
-         * @param listener The listener to be invoked.
-         * @see AdapterView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)
          *
-         * @return This Builder object to allow for chaining of calls to set methods
+         * @param listener the listener to be invoked
+         * @return this Builder object to allow for chaining of calls to set methods
+         * @see AdapterView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)
          */
         public Builder setOnItemSelectedListener(final AdapterView.OnItemSelectedListener listener) {
             P.mOnItemSelectedListener = listener;
             return this;
         }
-        
+
         /**
          * Set a custom view resource to be the contents of the Dialog. The
          * resource will be inflated, adding all top-level views to the screen.
          *
          * @param layoutResId Resource ID to be inflated.
-         * @return This Builder object to allow for chaining of calls to set
+         * @return this Builder object to allow for chaining of calls to set
          *         methods
          */
         public Builder setView(int layoutResId) {
@@ -897,12 +982,18 @@
         }
 
         /**
-         * Set a custom view to be the contents of the Dialog. If the supplied view is an instance
-         * of a {@link ListView} the light background will be used.
+         * Sets a custom view to be the contents of the alert dialog.
+         * <p>
+         * When using a pre-Holo theme, if the supplied view is an instance of
+         * a {@link ListView} then the light background will be used.
+         * <p>
+         * <strong>Note:</strong> To ensure consistent styling, the custom view
+         * should be inflated or constructed using the alert dialog's themed
+         * context obtained via {@link #getContext()}.
          *
-         * @param view The view to use as the contents of the Dialog.
-         * 
-         * @return This Builder object to allow for chaining of calls to set methods
+         * @param view the view to use as the contents of the alert dialog
+         * @return this Builder object to allow for chaining of calls to set
+         *         methods
          */
         public Builder setView(View view) {
             P.mView = view;
@@ -910,29 +1001,34 @@
             P.mViewSpacingSpecified = false;
             return this;
         }
-        
+
         /**
-         * Set a custom view to be the contents of the Dialog, specifying the
-         * spacing to appear around that view. If the supplied view is an
-         * instance of a {@link ListView} the light background will be used.
-         * 
-         * @param view The view to use as the contents of the Dialog.
-         * @param viewSpacingLeft Spacing between the left edge of the view and
-         *        the dialog frame
-         * @param viewSpacingTop Spacing between the top edge of the view and
-         *        the dialog frame
-         * @param viewSpacingRight Spacing between the right edge of the view
-         *        and the dialog frame
-         * @param viewSpacingBottom Spacing between the bottom edge of the view
-         *        and the dialog frame
-         * @return This Builder object to allow for chaining of calls to set
+         * Sets a custom view to be the contents of the alert dialog and
+         * specifies additional padding around that view.
+         * <p>
+         * When using a pre-Holo theme, if the supplied view is an instance of
+         * a {@link ListView} then the light background will be used.
+         * <p>
+         * <strong>Note:</strong> To ensure consistent styling, the custom view
+         * should be inflated or constructed using the alert dialog's themed
+         * context obtained via {@link #getContext()}.
+         *
+         * @param view the view to use as the contents of the alert dialog
+         * @param viewSpacingLeft spacing between the left edge of the view and
+         *                        the dialog frame
+         * @param viewSpacingTop spacing between the top edge of the view and
+         *                       the dialog frame
+         * @param viewSpacingRight spacing between the right edge of the view
+         *                         and the dialog frame
+         * @param viewSpacingBottom spacing between the bottom edge of the view
+         *                          and the dialog frame
+         * @return this Builder object to allow for chaining of calls to set
          *         methods
-         *         
-         * 
-         * This is currently hidden because it seems like people should just
-         * be able to put padding around the view.
-         * @hide
+         *
+         * @hide Remove once the framework usages have been replaced.
+         * @deprecated Set the padding on the view itself.
          */
+        @Deprecated
         public Builder setView(View view, int viewSpacingLeft, int viewSpacingTop,
                 int viewSpacingRight, int viewSpacingBottom) {
             P.mView = view;
@@ -944,15 +1040,18 @@
             P.mViewSpacingBottom = viewSpacingBottom;
             return this;
         }
-        
+
         /**
-         * Sets the Dialog to use the inverse background, regardless of what the
-         * contents is.
-         * 
-         * @param useInverseBackground Whether to use the inverse background
-         * 
-         * @return This Builder object to allow for chaining of calls to set methods
+         * Sets the alert dialog to use the inverse background, regardless of
+         * what the contents is.
+         *
+         * @param useInverseBackground whether to use the inverse background
+         * @return this Builder object to allow for chaining of calls to set methods
+         * @deprecated This flag is only used for pre-Material themes. Instead,
+         *             specify the window background using on the alert dialog
+         *             theme.
          */
+        @Deprecated
         public Builder setInverseBackgroundForced(boolean useInverseBackground) {
             P.mForceInverseBackground = useInverseBackground;
             return this;
@@ -968,13 +1067,15 @@
 
 
         /**
-         * Creates a {@link AlertDialog} with the arguments supplied to this builder. It does not
-         * {@link Dialog#show()} the dialog. This allows the user to do any extra processing
-         * before displaying the dialog. Use {@link #show()} if you don't have any other processing
-         * to do and want this to be created and displayed.
+         * Creates an {@link AlertDialog} with the arguments supplied to this
+         * builder.
+         * <p>
+         * Calling this method does not display the dialog. If no additional
+         * processing is needed, {@link #show()} may be called instead to both
+         * create and display the dialog.
          */
         public AlertDialog create() {
-            final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
+            final AlertDialog dialog = new AlertDialog(P.mContext, mThemeResId);
             P.apply(dialog.mAlert);
             dialog.setCancelable(P.mCancelable);
             if (P.mCancelable) {
@@ -989,14 +1090,20 @@
         }
 
         /**
-         * Creates a {@link AlertDialog} with the arguments supplied to this builder and
-         * {@link Dialog#show()}'s the dialog.
+         * Creates an {@link AlertDialog} with the arguments supplied to this
+         * builder and immediately displays the dialog.
+         * <p>
+         * Calling this method is functionally identical to:
+         * <pre>
+         *     AlertDialog dialog = builder.create();
+         *     dialog.show();
+         * </pre>
          */
         public AlertDialog show() {
-            AlertDialog dialog = create();
+            final AlertDialog dialog = create();
             dialog.show();
             return dialog;
         }
     }
-    
+
 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 503657b..eb27830 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -16,17 +16,9 @@
 
 package android.app;
 
-import android.app.usage.IUsageStatsManager;
-import android.app.usage.UsageStatsManager;
-import android.appwidget.AppWidgetManager;
-import android.os.Build;
-import android.service.persistentdata.IPersistentDataBlockService;
-import android.service.persistentdata.PersistentDataBlockManager;
-
-import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 
-import android.bluetooth.BluetoothManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentProvider;
@@ -34,19 +26,15 @@
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.IContentProvider;
+import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.IIntentReceiver;
 import android.content.IntentSender;
-import android.content.IRestrictionsManager;
 import android.content.ReceiverCallNotAllowedException;
-import android.content.RestrictionsManager;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.ILauncherApps;
 import android.content.pm.IPackageManager;
-import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.AssetManager;
@@ -58,101 +46,28 @@
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
-import android.hardware.ConsumerIrManager;
-import android.hardware.ISerialManager;
-import android.hardware.SerialManager;
-import android.hardware.SystemSensorManager;
-import android.hardware.hdmi.HdmiControlManager;
-import android.hardware.hdmi.IHdmiControlService;
-import android.hardware.camera2.CameraManager;
 import android.hardware.display.DisplayManager;
-import android.hardware.input.InputManager;
-import android.hardware.usb.IUsbManager;
-import android.hardware.usb.UsbManager;
-import android.location.CountryDetector;
-import android.location.ICountryDetector;
-import android.location.ILocationManager;
-import android.location.LocationManager;
-import android.media.AudioManager;
-import android.media.MediaRouter;
-import android.media.midi.IMidiManager;
-import android.media.midi.MidiManager;
-import android.media.projection.MediaProjectionManager;
-import android.media.session.MediaSessionManager;
-import android.media.tv.ITvInputManager;
-import android.media.tv.TvInputManager;
-import android.net.ConnectivityManager;
-import android.net.IConnectivityManager;
-import android.net.EthernetManager;
-import android.net.IEthernetManager;
-import android.net.INetworkPolicyManager;
-import android.net.NetworkPolicyManager;
-import android.net.NetworkScoreManager;
 import android.net.Uri;
-import android.net.nsd.INsdManager;
-import android.net.nsd.NsdManager;
-import android.net.wifi.IWifiManager;
-import android.net.wifi.WifiManager;
-import android.net.wifi.passpoint.IWifiPasspointManager;
-import android.net.wifi.passpoint.WifiPasspointManager;
-import android.net.wifi.p2p.IWifiP2pManager;
-import android.net.wifi.p2p.WifiP2pManager;
-import android.net.wifi.IWifiScanner;
-import android.net.wifi.WifiScanner;
-import android.net.wifi.IRttManager;
-import android.net.wifi.RttManager;
-import android.nfc.NfcManager;
-import android.os.BatteryManager;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
-import android.os.DropBoxManager;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.IPowerManager;
-import android.os.IUserManager;
 import android.os.Looper;
-import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
-import android.os.SystemVibrator;
-import android.os.UserManager;
 import android.os.storage.IMountService;
-import android.os.storage.StorageManager;
-import android.print.IPrintManager;
-import android.print.PrintManager;
-import android.service.fingerprint.IFingerprintService;
-import android.service.fingerprint.FingerprintManager;
-import android.telecom.TelecomManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.content.ClipboardManager;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
-import android.view.DisplayAdjustments;
-import android.view.ContextThemeWrapper;
 import android.view.Display;
-import android.view.PhoneLayoutInflater;
-import android.view.WindowManagerImpl;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.CaptioningManager;
-import android.view.inputmethod.InputMethodManager;
-import android.view.textservice.TextServicesManager;
-import android.accounts.AccountManager;
-import android.accounts.IAccountManager;
-import android.app.admin.DevicePolicyManager;
-import android.app.job.IJobScheduler;
-import android.app.trust.TrustManager;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.app.IAppOpsService;
-import com.android.internal.os.IDropBoxManagerService;
+import android.view.DisplayAdjustments;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -160,8 +75,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
 
 class ReceiverRestrictedContext extends ContextWrapper {
     ReceiverRestrictedContext(Context base) {
@@ -270,521 +183,8 @@
 
     private static final String[] EMPTY_FILE_LIST = {};
 
-    /**
-     * Override this class when the system service constructor needs a
-     * ContextImpl.  Else, use StaticServiceFetcher below.
-     */
-    /*package*/ static class ServiceFetcher {
-        int mContextCacheIndex = -1;
-
-        /**
-         * Main entrypoint; only override if you don't need caching.
-         */
-        public Object getService(ContextImpl ctx) {
-            ArrayList<Object> cache = ctx.mServiceCache;
-            Object service;
-            synchronized (cache) {
-                if (cache.size() == 0) {
-                    // Initialize the cache vector on first access.
-                    // At this point sNextPerContextServiceCacheIndex
-                    // is the number of potential services that are
-                    // cached per-Context.
-                    for (int i = 0; i < sNextPerContextServiceCacheIndex; i++) {
-                        cache.add(null);
-                    }
-                } else {
-                    service = cache.get(mContextCacheIndex);
-                    if (service != null) {
-                        return service;
-                    }
-                }
-                service = createService(ctx);
-                cache.set(mContextCacheIndex, service);
-                return service;
-            }
-        }
-
-        /**
-         * Override this to create a new per-Context instance of the
-         * service.  getService() will handle locking and caching.
-         */
-        public Object createService(ContextImpl ctx) {
-            throw new RuntimeException("Not implemented");
-        }
-    }
-
-    /**
-     * Override this class for services to be cached process-wide.
-     */
-    abstract static class StaticServiceFetcher extends ServiceFetcher {
-        private Object mCachedInstance;
-
-        @Override
-        public final Object getService(ContextImpl unused) {
-            synchronized (StaticServiceFetcher.this) {
-                Object service = mCachedInstance;
-                if (service != null) {
-                    return service;
-                }
-                return mCachedInstance = createStaticService();
-            }
-        }
-
-        public abstract Object createStaticService();
-    }
-
-    private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
-            new HashMap<String, ServiceFetcher>();
-
-    private static int sNextPerContextServiceCacheIndex = 0;
-    private static void registerService(String serviceName, ServiceFetcher fetcher) {
-        if (!(fetcher instanceof StaticServiceFetcher)) {
-            fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
-        }
-        SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
-    }
-
-    // This one's defined separately and given a variable name so it
-    // can be re-used by getWallpaperManager(), avoiding a HashMap
-    // lookup.
-    private static ServiceFetcher WALLPAPER_FETCHER = new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                return new WallpaperManager(ctx.getOuterContext(),
-                        ctx.mMainThread.getHandler());
-            }};
-
-    static {
-        registerService(ACCESSIBILITY_SERVICE, new ServiceFetcher() {
-                public Object getService(ContextImpl ctx) {
-                    return AccessibilityManager.getInstance(ctx);
-                }});
-
-        registerService(CAPTIONING_SERVICE, new ServiceFetcher() {
-                public Object getService(ContextImpl ctx) {
-                    return new CaptioningManager(ctx);
-                }});
-
-        registerService(ACCOUNT_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(ACCOUNT_SERVICE);
-                    IAccountManager service = IAccountManager.Stub.asInterface(b);
-                    return new AccountManager(ctx, service);
-                }});
-
-        registerService(ACTIVITY_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
-                }});
-
-        registerService(ALARM_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(ALARM_SERVICE);
-                    IAlarmManager service = IAlarmManager.Stub.asInterface(b);
-                    return new AlarmManager(service, ctx);
-                }});
-
-        registerService(AUDIO_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new AudioManager(ctx);
-                }});
-
-        registerService(MEDIA_ROUTER_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new MediaRouter(ctx);
-                }});
-
-        registerService(BLUETOOTH_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new BluetoothManager(ctx);
-                }});
-
-        registerService(HDMI_CONTROL_SERVICE, new StaticServiceFetcher() {
-                public Object createStaticService() {
-                    IBinder b = ServiceManager.getService(HDMI_CONTROL_SERVICE);
-                    return new HdmiControlManager(IHdmiControlService.Stub.asInterface(b));
-                }});
-
-        registerService(CLIPBOARD_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new ClipboardManager(ctx.getOuterContext(),
-                            ctx.mMainThread.getHandler());
-                }});
-
-        registerService(CONNECTIVITY_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
-                    return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b));
-                }});
-
-        registerService(COUNTRY_DETECTOR, new StaticServiceFetcher() {
-                public Object createStaticService() {
-                    IBinder b = ServiceManager.getService(COUNTRY_DETECTOR);
-                    return new CountryDetector(ICountryDetector.Stub.asInterface(b));
-                }});
-
-        registerService(DEVICE_POLICY_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return DevicePolicyManager.create(ctx, ctx.mMainThread.getHandler());
-                }});
-
-        registerService(DOWNLOAD_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new DownloadManager(ctx.getContentResolver(), ctx.getPackageName());
-                }});
-
-        registerService(BATTERY_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new BatteryManager();
-                }});
-
-        registerService(NFC_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new NfcManager(ctx);
-                }});
-
-        registerService(DROPBOX_SERVICE, new StaticServiceFetcher() {
-                public Object createStaticService() {
-                    return createDropBoxManager();
-                }});
-
-        registerService(INPUT_SERVICE, new StaticServiceFetcher() {
-                public Object createStaticService() {
-                    return InputManager.getInstance();
-                }});
-
-        registerService(DISPLAY_SERVICE, new ServiceFetcher() {
-                @Override
-                public Object createService(ContextImpl ctx) {
-                    return new DisplayManager(ctx.getOuterContext());
-                }});
-
-        registerService(INPUT_METHOD_SERVICE, new StaticServiceFetcher() {
-                public Object createStaticService() {
-                    return InputMethodManager.getInstance();
-                }});
-
-        registerService(TEXT_SERVICES_MANAGER_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return TextServicesManager.getInstance();
-                }});
-
-        registerService(KEYGUARD_SERVICE, new ServiceFetcher() {
-                public Object getService(ContextImpl ctx) {
-                    // TODO: why isn't this caching it?  It wasn't
-                    // before, so I'm preserving the old behavior and
-                    // using getService(), instead of createService()
-                    // which would do the caching.
-                    return new KeyguardManager();
-                }});
-
-        registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new PhoneLayoutInflater(ctx.getOuterContext());
-                }});
-
-        registerService(LOCATION_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(LOCATION_SERVICE);
-                    return new LocationManager(ctx, ILocationManager.Stub.asInterface(b));
-                }});
-
-        registerService(NETWORK_POLICY_SERVICE, new ServiceFetcher() {
-            @Override
-            public Object createService(ContextImpl ctx) {
-                return new NetworkPolicyManager(INetworkPolicyManager.Stub.asInterface(
-                        ServiceManager.getService(NETWORK_POLICY_SERVICE)));
-            }
-        });
-
-        registerService(NOTIFICATION_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    final Context outerContext = ctx.getOuterContext();
-                    return new NotificationManager(
-                        new ContextThemeWrapper(outerContext,
-                                Resources.selectSystemTheme(0,
-                                        outerContext.getApplicationInfo().targetSdkVersion,
-                                        com.android.internal.R.style.Theme_Dialog,
-                                        com.android.internal.R.style.Theme_Holo_Dialog,
-                                        com.android.internal.R.style.Theme_DeviceDefault_Dialog,
-                                        com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)),
-                        ctx.mMainThread.getHandler());
-                }});
-
-        registerService(NSD_SERVICE, new ServiceFetcher() {
-                @Override
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(NSD_SERVICE);
-                    INsdManager service = INsdManager.Stub.asInterface(b);
-                    return new NsdManager(ctx.getOuterContext(), service);
-                }});
-
-        // Note: this was previously cached in a static variable, but
-        // constructed using mMainThread.getHandler(), so converting
-        // it to be a regular Context-cached service...
-        registerService(POWER_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(POWER_SERVICE);
-                    IPowerManager service = IPowerManager.Stub.asInterface(b);
-                    if (service == null) {
-                        Log.wtf(TAG, "Failed to get power manager service.");
-                    }
-                    return new PowerManager(ctx.getOuterContext(),
-                            service, ctx.mMainThread.getHandler());
-                }});
-
-        registerService(SEARCH_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new SearchManager(ctx.getOuterContext(),
-                            ctx.mMainThread.getHandler());
-                }});
-
-        registerService(SENSOR_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new SystemSensorManager(ctx.getOuterContext(),
-                      ctx.mMainThread.getHandler().getLooper());
-                }});
-
-        registerService(STATUS_BAR_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new StatusBarManager(ctx.getOuterContext());
-                }});
-
-        registerService(STORAGE_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    try {
-                        return new StorageManager(
-                                ctx.getContentResolver(), ctx.mMainThread.getHandler().getLooper());
-                    } catch (RemoteException rex) {
-                        Log.e(TAG, "Failed to create StorageManager", rex);
-                        return null;
-                    }
-                }});
-
-        registerService(TELEPHONY_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new TelephonyManager(ctx.getOuterContext());
-                }});
-
-        registerService(TELEPHONY_SUBSCRIPTION_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                return new SubscriptionManager(ctx.getOuterContext());
-            }});
-
-        registerService(TELECOM_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new TelecomManager(ctx.getOuterContext());
-                }});
-
-        registerService(UI_MODE_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new UiModeManager();
-                }});
-
-        registerService(USB_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(USB_SERVICE);
-                    return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
-                }});
-
-        registerService(SERIAL_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(SERIAL_SERVICE);
-                    return new SerialManager(ctx, ISerialManager.Stub.asInterface(b));
-                }});
-
-        registerService(VIBRATOR_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new SystemVibrator(ctx);
-                }});
-
-        registerService(WALLPAPER_SERVICE, WALLPAPER_FETCHER);
-
-        registerService(WIFI_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(WIFI_SERVICE);
-                    IWifiManager service = IWifiManager.Stub.asInterface(b);
-                    return new WifiManager(ctx.getOuterContext(), service);
-                }});
-
-        registerService(WIFI_PASSPOINT_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(WIFI_PASSPOINT_SERVICE);
-                    IWifiPasspointManager service = IWifiPasspointManager.Stub.asInterface(b);
-                    return new WifiPasspointManager(ctx.getOuterContext(), service);
-                }});
-
-        registerService(WIFI_P2P_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(WIFI_P2P_SERVICE);
-                    IWifiP2pManager service = IWifiP2pManager.Stub.asInterface(b);
-                    return new WifiP2pManager(service);
-                }});
-
-        registerService(WIFI_SCANNING_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(WIFI_SCANNING_SERVICE);
-                IWifiScanner service = IWifiScanner.Stub.asInterface(b);
-                return new WifiScanner(ctx.getOuterContext(), service);
-            }});
-
-        registerService(WIFI_RTT_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(WIFI_RTT_SERVICE);
-                IRttManager service = IRttManager.Stub.asInterface(b);
-                return new RttManager(ctx.getOuterContext(), service);
-            }});
-
-        registerService(ETHERNET_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(ETHERNET_SERVICE);
-                    IEthernetManager service = IEthernetManager.Stub.asInterface(b);
-                    return new EthernetManager(ctx.getOuterContext(), service);
-                }});
-
-        registerService(WINDOW_SERVICE, new ServiceFetcher() {
-                Display mDefaultDisplay;
-                public Object getService(ContextImpl ctx) {
-                    Display display = ctx.mDisplay;
-                    if (display == null) {
-                        if (mDefaultDisplay == null) {
-                            DisplayManager dm = (DisplayManager)ctx.getOuterContext().
-                                    getSystemService(Context.DISPLAY_SERVICE);
-                            mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
-                        }
-                        display = mDefaultDisplay;
-                    }
-                    return new WindowManagerImpl(display);
-                }});
-
-        registerService(USER_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(USER_SERVICE);
-                IUserManager service = IUserManager.Stub.asInterface(b);
-                return new UserManager(ctx, service);
-            }});
-
-        registerService(APP_OPS_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(APP_OPS_SERVICE);
-                IAppOpsService service = IAppOpsService.Stub.asInterface(b);
-                return new AppOpsManager(ctx, service);
-            }});
-
-        registerService(CAMERA_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                return new CameraManager(ctx);
-            }
-        });
-
-        registerService(LAUNCHER_APPS_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(LAUNCHER_APPS_SERVICE);
-                ILauncherApps service = ILauncherApps.Stub.asInterface(b);
-                return new LauncherApps(ctx, service);
-            }
-        });
-
-        registerService(RESTRICTIONS_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(RESTRICTIONS_SERVICE);
-                IRestrictionsManager service = IRestrictionsManager.Stub.asInterface(b);
-                return new RestrictionsManager(ctx, service);
-            }
-        });
-        registerService(PRINT_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder iBinder = ServiceManager.getService(Context.PRINT_SERVICE);
-                IPrintManager service = IPrintManager.Stub.asInterface(iBinder);
-                return new PrintManager(ctx.getOuterContext(), service, UserHandle.myUserId(),
-                        UserHandle.getAppId(Process.myUid()));
-            }});
-
-        registerService(CONSUMER_IR_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                return new ConsumerIrManager(ctx);
-            }});
-
-        registerService(MEDIA_SESSION_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                return new MediaSessionManager(ctx);
-            }
-        });
-
-        registerService(TRUST_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(TRUST_SERVICE);
-                return new TrustManager(b);
-            }
-        });
-
-        registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder binder = ServiceManager.getService(FINGERPRINT_SERVICE);
-                IFingerprintService service = IFingerprintService.Stub.asInterface(binder);
-                return new FingerprintManager(ctx.getOuterContext(), service);
-            }
-        });
-
-        registerService(TV_INPUT_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder iBinder = ServiceManager.getService(TV_INPUT_SERVICE);
-                ITvInputManager service = ITvInputManager.Stub.asInterface(iBinder);
-                return new TvInputManager(service, UserHandle.myUserId());
-            }
-        });
-
-        registerService(NETWORK_SCORE_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                return new NetworkScoreManager(ctx);
-            }
-        });
-
-        registerService(USAGE_STATS_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder iBinder = ServiceManager.getService(USAGE_STATS_SERVICE);
-                IUsageStatsManager service = IUsageStatsManager.Stub.asInterface(iBinder);
-                return new UsageStatsManager(ctx.getOuterContext(), service);
-            }
-        });
-
-        registerService(JOB_SCHEDULER_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(JOB_SCHEDULER_SERVICE);
-                return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
-        }});
-
-        registerService(PERSISTENT_DATA_BLOCK_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(PERSISTENT_DATA_BLOCK_SERVICE);
-                IPersistentDataBlockService persistentDataBlockService =
-                        IPersistentDataBlockService.Stub.asInterface(b);
-                if (persistentDataBlockService != null) {
-                    return new PersistentDataBlockManager(persistentDataBlockService);
-                } else {
-                    // not supported
-                    return null;
-                }
-            }
-        });
-
-        registerService(MEDIA_PROJECTION_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    return new MediaProjectionManager(ctx);
-                }
-        });
-
-        registerService(APPWIDGET_SERVICE, new ServiceFetcher() {
-            public Object createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(APPWIDGET_SERVICE);
-                return new AppWidgetManager(ctx, IAppWidgetService.Stub.asInterface(b));
-            }});
-
-        registerService(MIDI_SERVICE, new ServiceFetcher() {
-                public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(MIDI_SERVICE);
-                    return new MidiManager(ctx, IMidiManager.Stub.asInterface(b));
-                }});
-    }
+    // The system service cache for the system services that are cached per-ContextImpl.
+    final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();
 
     static ContextImpl getImpl(Context context) {
         Context nextContext;
@@ -795,11 +195,6 @@
         return (ContextImpl)context;
     }
 
-    // The system service cache for the system services that are
-    // cached per-ContextImpl.  Package-scoped to avoid accessor
-    // methods.
-    final ArrayList<Object> mServiceCache = new ArrayList<Object>();
-
     @Override
     public AssetManager getAssets() {
         return getResources().getAssets();
@@ -914,6 +309,7 @@
         throw new RuntimeException("Not supported in system context");
     }
 
+    @Override
     public File getSharedPrefsFile(String name) {
         return makeFilename(getPreferencesDir(), name + ".xml");
     }
@@ -1201,40 +597,51 @@
     }
 
     @Override
+    @Deprecated
     public Drawable getWallpaper() {
         return getWallpaperManager().getDrawable();
     }
 
     @Override
+    @Deprecated
     public Drawable peekWallpaper() {
         return getWallpaperManager().peekDrawable();
     }
 
     @Override
+    @Deprecated
     public int getWallpaperDesiredMinimumWidth() {
         return getWallpaperManager().getDesiredMinimumWidth();
     }
 
     @Override
+    @Deprecated
     public int getWallpaperDesiredMinimumHeight() {
         return getWallpaperManager().getDesiredMinimumHeight();
     }
 
     @Override
-    public void setWallpaper(Bitmap bitmap) throws IOException  {
+    @Deprecated
+    public void setWallpaper(Bitmap bitmap) throws IOException {
         getWallpaperManager().setBitmap(bitmap);
     }
 
     @Override
+    @Deprecated
     public void setWallpaper(InputStream data) throws IOException {
         getWallpaperManager().setStream(data);
     }
 
     @Override
+    @Deprecated
     public void clearWallpaper() throws IOException {
         getWallpaperManager().clear();
     }
 
+    private WallpaperManager getWallpaperManager() {
+        return getSystemService(WallpaperManager.class);
+    }
+
     @Override
     public void startActivity(Intent intent) {
         warnIfCallingFromSystemProcess();
@@ -1506,6 +913,7 @@
     }
 
     @Override
+    @Deprecated
     public void sendStickyBroadcast(Intent intent) {
         warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1520,6 +928,7 @@
     }
 
     @Override
+    @Deprecated
     public void sendStickyOrderedBroadcast(Intent intent,
             BroadcastReceiver resultReceiver,
             Handler scheduler, int initialCode, String initialData,
@@ -1554,6 +963,7 @@
     }
 
     @Override
+    @Deprecated
     public void removeStickyBroadcast(Intent intent) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         if (resolvedType != null) {
@@ -1569,6 +979,7 @@
     }
 
     @Override
+    @Deprecated
     public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
@@ -1581,6 +992,7 @@
     }
 
     @Override
+    @Deprecated
     public void sendStickyOrderedBroadcastAsUser(Intent intent,
             UserHandle user, BroadcastReceiver resultReceiver,
             Handler scheduler, int initialCode, String initialData,
@@ -1614,6 +1026,7 @@
     }
 
     @Override
+    @Deprecated
     public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         if (resolvedType != null) {
@@ -1850,25 +1263,12 @@
 
     @Override
     public Object getSystemService(String name) {
-        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
-        return fetcher == null ? null : fetcher.getService(this);
+        return SystemServiceRegistry.getSystemService(this, name);
     }
 
-    private WallpaperManager getWallpaperManager() {
-        return (WallpaperManager) WALLPAPER_FETCHER.getService(this);
-    }
-
-    /* package */ static DropBoxManager createDropBoxManager() {
-        IBinder b = ServiceManager.getService(DROPBOX_SERVICE);
-        IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b);
-        if (service == null) {
-            // Don't return a DropBoxManager that will NPE upon use.
-            // This also avoids caching a broken DropBoxManager in
-            // getDropBoxManager during early boot, before the
-            // DROPBOX_SERVICE is registered.
-            return null;
-        }
-        return new DropBoxManager(service);
+    @Override
+    public String getSystemServiceName(Class<?> serviceClass) {
+        return SystemServiceRegistry.getSystemServiceName(serviceClass);
     }
 
     @Override
@@ -1937,6 +1337,7 @@
         }
     }
 
+    @Override
     public void enforcePermission(
             String permission, int pid, int uid, String message) {
         enforce(permission,
@@ -1946,6 +1347,7 @@
                 message);
     }
 
+    @Override
     public void enforceCallingPermission(String permission, String message) {
         enforce(permission,
                 checkCallingPermission(permission),
@@ -1954,6 +1356,7 @@
                 message);
     }
 
+    @Override
     public void enforceCallingOrSelfPermission(
             String permission, String message) {
         enforce(permission,
@@ -2091,6 +1494,7 @@
         }
     }
 
+    @Override
     public void enforceUriPermission(
             Uri uri, int pid, int uid, int modeFlags, String message) {
         enforceForUri(
@@ -2098,6 +1502,7 @@
                 false, uid, uri, message);
     }
 
+    @Override
     public void enforceCallingUriPermission(
             Uri uri, int modeFlags, String message) {
         enforceForUri(
@@ -2106,6 +1511,7 @@
                 Binder.getCallingUid(), uri, message);
     }
 
+    @Override
     public void enforceCallingOrSelfUriPermission(
             Uri uri, int modeFlags, String message) {
         enforceForUri(
@@ -2114,6 +1520,7 @@
                 Binder.getCallingUid(), uri, message);
     }
 
+    @Override
     public void enforceUriPermission(
             Uri uri, String readPermission, String writePermission,
             int pid, int uid, int modeFlags, String message) {
@@ -2209,6 +1616,14 @@
                 mUser, mRestricted, display, null);
     }
 
+    Display getDisplay() {
+        if (mDisplay != null) {
+            return mDisplay;
+        }
+        DisplayManager dm = getSystemService(DisplayManager.class);
+        return dm.getDisplay(Display.DEFAULT_DISPLAY);
+    }
+
     private int getDisplayId() {
         return mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
     }
@@ -2243,6 +1658,7 @@
     }
 
     /** {@hide} */
+    @Override
     public int getUserId() {
         return mUser.getIdentifier();
     }
@@ -2368,6 +1784,7 @@
         return mActivityToken;
     }
 
+    @SuppressWarnings("deprecation")
     static void setFilePermissionsFromMode(String name, int mode,
             int extraPermissions) {
         int perms = FileUtils.S_IRUSR|FileUtils.S_IWUSR
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
new file mode 100644
index 0000000..993f416
--- /dev/null
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -0,0 +1,776 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.os.IDropBoxManagerService;
+
+import android.accounts.AccountManager;
+import android.accounts.IAccountManager;
+import android.app.admin.DevicePolicyManager;
+import android.app.job.IJobScheduler;
+import android.app.job.JobScheduler;
+import android.app.trust.TrustManager;
+import android.app.usage.IUsageStatsManager;
+import android.app.usage.UsageStatsManager;
+import android.appwidget.AppWidgetManager;
+import android.bluetooth.BluetoothManager;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.content.IRestrictionsManager;
+import android.content.RestrictionsManager;
+import android.content.pm.ILauncherApps;
+import android.content.pm.LauncherApps;
+import android.content.res.Resources;
+import android.hardware.ConsumerIrManager;
+import android.hardware.ISerialManager;
+import android.hardware.SensorManager;
+import android.hardware.SerialManager;
+import android.hardware.SystemSensorManager;
+import android.hardware.camera2.CameraManager;
+import android.hardware.display.DisplayManager;
+import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.IHdmiControlService;
+import android.hardware.input.InputManager;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbManager;
+import android.location.CountryDetector;
+import android.location.ICountryDetector;
+import android.location.ILocationManager;
+import android.location.LocationManager;
+import android.media.AudioManager;
+import android.media.MediaRouter;
+import android.media.midi.IMidiManager;
+import android.media.midi.MidiManager;
+import android.media.projection.MediaProjectionManager;
+import android.media.session.MediaSessionManager;
+import android.media.tv.ITvInputManager;
+import android.media.tv.TvInputManager;
+import android.net.ConnectivityManager;
+import android.net.EthernetManager;
+import android.net.IConnectivityManager;
+import android.net.IEthernetManager;
+import android.net.INetworkPolicyManager;
+import android.net.NetworkPolicyManager;
+import android.net.NetworkScoreManager;
+import android.net.nsd.INsdManager;
+import android.net.nsd.NsdManager;
+import android.net.wifi.IRttManager;
+import android.net.wifi.IWifiManager;
+import android.net.wifi.IWifiScanner;
+import android.net.wifi.RttManager;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiScanner;
+import android.net.wifi.p2p.IWifiP2pManager;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.net.wifi.passpoint.IWifiPasspointManager;
+import android.net.wifi.passpoint.WifiPasspointManager;
+import android.nfc.NfcManager;
+import android.os.BatteryManager;
+import android.os.DropBoxManager;
+import android.os.IBinder;
+import android.os.IPowerManager;
+import android.os.IUserManager;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemVibrator;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.Vibrator;
+import android.os.storage.StorageManager;
+import android.print.IPrintManager;
+import android.print.PrintManager;
+import android.service.fingerprint.FingerprintManager;
+import android.service.fingerprint.IFingerprintService;
+import android.service.persistentdata.IPersistentDataBlockService;
+import android.service.persistentdata.PersistentDataBlockManager;
+import android.telecom.TelecomManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.PhoneLayoutInflater;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.CaptioningManager;
+import android.view.inputmethod.InputMethodManager;
+import android.view.textservice.TextServicesManager;
+
+import java.util.HashMap;
+
+/**
+ * Manages all of the system services that can be returned by {@link Context#getSystemService}.
+ * Used by {@link ContextImpl}.
+ */
+final class SystemServiceRegistry {
+    private final static String TAG = "SystemServiceRegistry";
+
+    // Service registry information.
+    // This information is never changed once static initialization has completed.
+    private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
+            new HashMap<Class<?>, String>();
+    private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
+            new HashMap<String, ServiceFetcher<?>>();
+    private static int sServiceCacheSize;
+
+    // Not instantiable.
+    private SystemServiceRegistry() { }
+
+    static {
+        registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
+                new CachedServiceFetcher<AccessibilityManager>() {
+            @Override
+            public AccessibilityManager createService(ContextImpl ctx) {
+                return AccessibilityManager.getInstance(ctx);
+            }});
+
+        registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class,
+                new CachedServiceFetcher<CaptioningManager>() {
+            @Override
+            public CaptioningManager createService(ContextImpl ctx) {
+                return new CaptioningManager(ctx);
+            }});
+
+        registerService(Context.ACCOUNT_SERVICE, AccountManager.class,
+                new CachedServiceFetcher<AccountManager>() {
+            @Override
+            public AccountManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.ACCOUNT_SERVICE);
+                IAccountManager service = IAccountManager.Stub.asInterface(b);
+                return new AccountManager(ctx, service);
+            }});
+
+        registerService(Context.ACTIVITY_SERVICE, ActivityManager.class,
+                new CachedServiceFetcher<ActivityManager>() {
+            @Override
+            public ActivityManager createService(ContextImpl ctx) {
+                return new ActivityManager(ctx.getOuterContext(), ctx.mMainThread.getHandler());
+            }});
+
+        registerService(Context.ALARM_SERVICE, AlarmManager.class,
+                new CachedServiceFetcher<AlarmManager>() {
+            @Override
+            public AlarmManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);
+                IAlarmManager service = IAlarmManager.Stub.asInterface(b);
+                return new AlarmManager(service, ctx);
+            }});
+
+        registerService(Context.AUDIO_SERVICE, AudioManager.class,
+                new CachedServiceFetcher<AudioManager>() {
+            @Override
+            public AudioManager createService(ContextImpl ctx) {
+                return new AudioManager(ctx);
+            }});
+
+        registerService(Context.MEDIA_ROUTER_SERVICE, MediaRouter.class,
+                new CachedServiceFetcher<MediaRouter>() {
+            @Override
+            public MediaRouter createService(ContextImpl ctx) {
+                return new MediaRouter(ctx);
+            }});
+
+        registerService(Context.BLUETOOTH_SERVICE, BluetoothManager.class,
+                new CachedServiceFetcher<BluetoothManager>() {
+            @Override
+            public BluetoothManager createService(ContextImpl ctx) {
+                return new BluetoothManager(ctx);
+            }});
+
+        registerService(Context.HDMI_CONTROL_SERVICE, HdmiControlManager.class,
+                new StaticServiceFetcher<HdmiControlManager>() {
+            @Override
+            public HdmiControlManager createService() {
+                IBinder b = ServiceManager.getService(Context.HDMI_CONTROL_SERVICE);
+                return new HdmiControlManager(IHdmiControlService.Stub.asInterface(b));
+            }});
+
+        registerService(Context.CLIPBOARD_SERVICE, ClipboardManager.class,
+                new CachedServiceFetcher<ClipboardManager>() {
+            @Override
+            public ClipboardManager createService(ContextImpl ctx) {
+                return new ClipboardManager(ctx.getOuterContext(),
+                        ctx.mMainThread.getHandler());
+            }});
+
+        // The clipboard service moved to a new package.  If someone asks for the old
+        // interface by class then we want to redirect over to the new interface instead
+        // (which extends it).
+        SYSTEM_SERVICE_NAMES.put(android.text.ClipboardManager.class, Context.CLIPBOARD_SERVICE);
+
+        registerService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class,
+                new StaticServiceFetcher<ConnectivityManager>() {
+            @Override
+            public ConnectivityManager createService() {
+                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+                return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b));
+            }});
+
+        registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
+                new StaticServiceFetcher<CountryDetector>() {
+            @Override
+            public CountryDetector createService() {
+                IBinder b = ServiceManager.getService(Context.COUNTRY_DETECTOR);
+                return new CountryDetector(ICountryDetector.Stub.asInterface(b));
+            }});
+
+        registerService(Context.DEVICE_POLICY_SERVICE, DevicePolicyManager.class,
+                new CachedServiceFetcher<DevicePolicyManager>() {
+            @Override
+            public DevicePolicyManager createService(ContextImpl ctx) {
+                return DevicePolicyManager.create(ctx, ctx.mMainThread.getHandler());
+            }});
+
+        registerService(Context.DOWNLOAD_SERVICE, DownloadManager.class,
+                new CachedServiceFetcher<DownloadManager>() {
+            @Override
+            public DownloadManager createService(ContextImpl ctx) {
+                return new DownloadManager(ctx.getContentResolver(), ctx.getPackageName());
+            }});
+
+        registerService(Context.BATTERY_SERVICE, BatteryManager.class,
+                new StaticServiceFetcher<BatteryManager>() {
+            @Override
+            public BatteryManager createService() {
+                return new BatteryManager();
+            }});
+
+        registerService(Context.NFC_SERVICE, NfcManager.class,
+                new CachedServiceFetcher<NfcManager>() {
+            @Override
+            public NfcManager createService(ContextImpl ctx) {
+                return new NfcManager(ctx);
+            }});
+
+        registerService(Context.DROPBOX_SERVICE, DropBoxManager.class,
+                new StaticServiceFetcher<DropBoxManager>() {
+            @Override
+            public DropBoxManager createService() {
+                IBinder b = ServiceManager.getService(Context.DROPBOX_SERVICE);
+                IDropBoxManagerService service = IDropBoxManagerService.Stub.asInterface(b);
+                if (service == null) {
+                    // Don't return a DropBoxManager that will NPE upon use.
+                    // This also avoids caching a broken DropBoxManager in
+                    // getDropBoxManager during early boot, before the
+                    // DROPBOX_SERVICE is registered.
+                    return null;
+                }
+                return new DropBoxManager(service);
+            }});
+
+        registerService(Context.INPUT_SERVICE, InputManager.class,
+                new StaticServiceFetcher<InputManager>() {
+            @Override
+            public InputManager createService() {
+                return InputManager.getInstance();
+            }});
+
+        registerService(Context.DISPLAY_SERVICE, DisplayManager.class,
+                new CachedServiceFetcher<DisplayManager>() {
+            @Override
+            public DisplayManager createService(ContextImpl ctx) {
+                return new DisplayManager(ctx.getOuterContext());
+            }});
+
+        registerService(Context.INPUT_METHOD_SERVICE, InputMethodManager.class,
+                new StaticServiceFetcher<InputMethodManager>() {
+            @Override
+            public InputMethodManager createService() {
+                return InputMethodManager.getInstance();
+            }});
+
+        registerService(Context.TEXT_SERVICES_MANAGER_SERVICE, TextServicesManager.class,
+                new StaticServiceFetcher<TextServicesManager>() {
+            @Override
+            public TextServicesManager createService() {
+                return TextServicesManager.getInstance();
+            }});
+
+        registerService(Context.KEYGUARD_SERVICE, KeyguardManager.class,
+                new StaticServiceFetcher<KeyguardManager>() {
+            @Override
+            public KeyguardManager createService() {
+                return new KeyguardManager();
+            }});
+
+        registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
+                new CachedServiceFetcher<LayoutInflater>() {
+            @Override
+            public LayoutInflater createService(ContextImpl ctx) {
+                return new PhoneLayoutInflater(ctx.getOuterContext());
+            }});
+
+        registerService(Context.LOCATION_SERVICE, LocationManager.class,
+                new CachedServiceFetcher<LocationManager>() {
+            @Override
+            public LocationManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
+                return new LocationManager(ctx, ILocationManager.Stub.asInterface(b));
+            }});
+
+        registerService(Context.NETWORK_POLICY_SERVICE, NetworkPolicyManager.class,
+                new StaticServiceFetcher<NetworkPolicyManager>() {
+            @Override
+            public NetworkPolicyManager createService() {
+                return new NetworkPolicyManager(INetworkPolicyManager.Stub.asInterface(
+                        ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)));
+            }});
+
+        registerService(Context.NOTIFICATION_SERVICE, NotificationManager.class,
+                new CachedServiceFetcher<NotificationManager>() {
+            @Override
+            public NotificationManager createService(ContextImpl ctx) {
+                final Context outerContext = ctx.getOuterContext();
+                return new NotificationManager(
+                    new ContextThemeWrapper(outerContext,
+                            Resources.selectSystemTheme(0,
+                                    outerContext.getApplicationInfo().targetSdkVersion,
+                                    com.android.internal.R.style.Theme_Dialog,
+                                    com.android.internal.R.style.Theme_Holo_Dialog,
+                                    com.android.internal.R.style.Theme_DeviceDefault_Dialog,
+                                    com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)),
+                    ctx.mMainThread.getHandler());
+            }});
+
+        registerService(Context.NSD_SERVICE, NsdManager.class,
+                new CachedServiceFetcher<NsdManager>() {
+            @Override
+            public NsdManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.NSD_SERVICE);
+                INsdManager service = INsdManager.Stub.asInterface(b);
+                return new NsdManager(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.POWER_SERVICE, PowerManager.class,
+                new CachedServiceFetcher<PowerManager>() {
+            @Override
+            public PowerManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
+                IPowerManager service = IPowerManager.Stub.asInterface(b);
+                if (service == null) {
+                    Log.wtf(TAG, "Failed to get power manager service.");
+                }
+                return new PowerManager(ctx.getOuterContext(),
+                        service, ctx.mMainThread.getHandler());
+            }});
+
+        registerService(Context.SEARCH_SERVICE, SearchManager.class,
+                new CachedServiceFetcher<SearchManager>() {
+            @Override
+            public SearchManager createService(ContextImpl ctx) {
+                return new SearchManager(ctx.getOuterContext(),
+                        ctx.mMainThread.getHandler());
+            }});
+
+        registerService(Context.SENSOR_SERVICE, SensorManager.class,
+                new CachedServiceFetcher<SensorManager>() {
+            @Override
+            public SensorManager createService(ContextImpl ctx) {
+                return new SystemSensorManager(ctx.getOuterContext(),
+                  ctx.mMainThread.getHandler().getLooper());
+            }});
+
+        registerService(Context.STATUS_BAR_SERVICE, StatusBarManager.class,
+                new CachedServiceFetcher<StatusBarManager>() {
+            @Override
+            public StatusBarManager createService(ContextImpl ctx) {
+                return new StatusBarManager(ctx.getOuterContext());
+            }});
+
+        registerService(Context.STORAGE_SERVICE, StorageManager.class,
+                new CachedServiceFetcher<StorageManager>() {
+            @Override
+            public StorageManager createService(ContextImpl ctx) {
+                try {
+                    return new StorageManager(
+                            ctx.getContentResolver(), ctx.mMainThread.getHandler().getLooper());
+                } catch (RemoteException rex) {
+                    Log.e(TAG, "Failed to create StorageManager", rex);
+                    return null;
+                }
+            }});
+
+        registerService(Context.TELEPHONY_SERVICE, TelephonyManager.class,
+                new CachedServiceFetcher<TelephonyManager>() {
+            @Override
+            public TelephonyManager createService(ContextImpl ctx) {
+                return new TelephonyManager(ctx.getOuterContext());
+            }});
+
+        registerService(Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class,
+                new CachedServiceFetcher<SubscriptionManager>() {
+            @Override
+            public SubscriptionManager createService(ContextImpl ctx) {
+                return new SubscriptionManager(ctx.getOuterContext());
+            }});
+
+        registerService(Context.TELECOM_SERVICE, TelecomManager.class,
+                new CachedServiceFetcher<TelecomManager>() {
+            @Override
+            public TelecomManager createService(ContextImpl ctx) {
+                return new TelecomManager(ctx.getOuterContext());
+            }});
+
+        registerService(Context.UI_MODE_SERVICE, UiModeManager.class,
+                new CachedServiceFetcher<UiModeManager>() {
+            @Override
+            public UiModeManager createService(ContextImpl ctx) {
+                return new UiModeManager();
+            }});
+
+        registerService(Context.USB_SERVICE, UsbManager.class,
+                new CachedServiceFetcher<UsbManager>() {
+            @Override
+            public UsbManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.USB_SERVICE);
+                return new UsbManager(ctx, IUsbManager.Stub.asInterface(b));
+            }});
+
+        registerService(Context.SERIAL_SERVICE, SerialManager.class,
+                new CachedServiceFetcher<SerialManager>() {
+            @Override
+            public SerialManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.SERIAL_SERVICE);
+                return new SerialManager(ctx, ISerialManager.Stub.asInterface(b));
+            }});
+
+        registerService(Context.VIBRATOR_SERVICE, Vibrator.class,
+                new CachedServiceFetcher<Vibrator>() {
+            @Override
+            public Vibrator createService(ContextImpl ctx) {
+                return new SystemVibrator(ctx);
+            }});
+
+        registerService(Context.WALLPAPER_SERVICE, WallpaperManager.class,
+                new CachedServiceFetcher<WallpaperManager>() {
+            @Override
+            public WallpaperManager createService(ContextImpl ctx) {
+                return new WallpaperManager(ctx.getOuterContext(),
+                        ctx.mMainThread.getHandler());
+            }});
+
+        registerService(Context.WIFI_SERVICE, WifiManager.class,
+                new CachedServiceFetcher<WifiManager>() {
+            @Override
+            public WifiManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.WIFI_SERVICE);
+                IWifiManager service = IWifiManager.Stub.asInterface(b);
+                return new WifiManager(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.WIFI_PASSPOINT_SERVICE, WifiPasspointManager.class,
+                new CachedServiceFetcher<WifiPasspointManager>() {
+            @Override
+            public WifiPasspointManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE);
+                IWifiPasspointManager service = IWifiPasspointManager.Stub.asInterface(b);
+                return new WifiPasspointManager(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.WIFI_P2P_SERVICE, WifiP2pManager.class,
+                new StaticServiceFetcher<WifiP2pManager>() {
+            @Override
+            public WifiP2pManager createService() {
+                IBinder b = ServiceManager.getService(Context.WIFI_P2P_SERVICE);
+                IWifiP2pManager service = IWifiP2pManager.Stub.asInterface(b);
+                return new WifiP2pManager(service);
+            }});
+
+        registerService(Context.WIFI_SCANNING_SERVICE, WifiScanner.class,
+                new CachedServiceFetcher<WifiScanner>() {
+            @Override
+            public WifiScanner createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.WIFI_SCANNING_SERVICE);
+                IWifiScanner service = IWifiScanner.Stub.asInterface(b);
+                return new WifiScanner(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.WIFI_RTT_SERVICE, RttManager.class,
+                new CachedServiceFetcher<RttManager>() {
+            @Override
+            public RttManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.WIFI_RTT_SERVICE);
+                IRttManager service = IRttManager.Stub.asInterface(b);
+                return new RttManager(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.ETHERNET_SERVICE, EthernetManager.class,
+                new CachedServiceFetcher<EthernetManager>() {
+            @Override
+            public EthernetManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.ETHERNET_SERVICE);
+                IEthernetManager service = IEthernetManager.Stub.asInterface(b);
+                return new EthernetManager(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.WINDOW_SERVICE, WindowManager.class,
+                new CachedServiceFetcher<WindowManager>() {
+            @Override
+            public WindowManager createService(ContextImpl ctx) {
+                return new WindowManagerImpl(ctx.getDisplay());
+            }});
+
+        registerService(Context.USER_SERVICE, UserManager.class,
+                new CachedServiceFetcher<UserManager>() {
+            @Override
+            public UserManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.USER_SERVICE);
+                IUserManager service = IUserManager.Stub.asInterface(b);
+                return new UserManager(ctx, service);
+            }});
+
+        registerService(Context.APP_OPS_SERVICE, AppOpsManager.class,
+                new CachedServiceFetcher<AppOpsManager>() {
+            @Override
+            public AppOpsManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
+                IAppOpsService service = IAppOpsService.Stub.asInterface(b);
+                return new AppOpsManager(ctx, service);
+            }});
+
+        registerService(Context.CAMERA_SERVICE, CameraManager.class,
+                new CachedServiceFetcher<CameraManager>() {
+            @Override
+            public CameraManager createService(ContextImpl ctx) {
+                return new CameraManager(ctx);
+            }});
+
+        registerService(Context.LAUNCHER_APPS_SERVICE, LauncherApps.class,
+                new CachedServiceFetcher<LauncherApps>() {
+            @Override
+            public LauncherApps createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE);
+                ILauncherApps service = ILauncherApps.Stub.asInterface(b);
+                return new LauncherApps(ctx, service);
+            }});
+
+        registerService(Context.RESTRICTIONS_SERVICE, RestrictionsManager.class,
+                new CachedServiceFetcher<RestrictionsManager>() {
+            @Override
+            public RestrictionsManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.RESTRICTIONS_SERVICE);
+                IRestrictionsManager service = IRestrictionsManager.Stub.asInterface(b);
+                return new RestrictionsManager(ctx, service);
+            }});
+
+        registerService(Context.PRINT_SERVICE, PrintManager.class,
+                new CachedServiceFetcher<PrintManager>() {
+            @Override
+            public PrintManager createService(ContextImpl ctx) {
+                IBinder iBinder = ServiceManager.getService(Context.PRINT_SERVICE);
+                IPrintManager service = IPrintManager.Stub.asInterface(iBinder);
+                return new PrintManager(ctx.getOuterContext(), service, UserHandle.myUserId(),
+                        UserHandle.getAppId(Process.myUid()));
+            }});
+
+        registerService(Context.CONSUMER_IR_SERVICE, ConsumerIrManager.class,
+                new CachedServiceFetcher<ConsumerIrManager>() {
+            @Override
+            public ConsumerIrManager createService(ContextImpl ctx) {
+                return new ConsumerIrManager(ctx);
+            }});
+
+        registerService(Context.MEDIA_SESSION_SERVICE, MediaSessionManager.class,
+                new CachedServiceFetcher<MediaSessionManager>() {
+            @Override
+            public MediaSessionManager createService(ContextImpl ctx) {
+                return new MediaSessionManager(ctx);
+            }});
+
+        registerService(Context.TRUST_SERVICE, TrustManager.class,
+                new StaticServiceFetcher<TrustManager>() {
+            @Override
+            public TrustManager createService() {
+                IBinder b = ServiceManager.getService(Context.TRUST_SERVICE);
+                return new TrustManager(b);
+            }});
+
+        registerService(Context.FINGERPRINT_SERVICE, FingerprintManager.class,
+                new CachedServiceFetcher<FingerprintManager>() {
+            @Override
+            public FingerprintManager createService(ContextImpl ctx) {
+                IBinder binder = ServiceManager.getService(Context.FINGERPRINT_SERVICE);
+                IFingerprintService service = IFingerprintService.Stub.asInterface(binder);
+                return new FingerprintManager(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.TV_INPUT_SERVICE, TvInputManager.class,
+                new StaticServiceFetcher<TvInputManager>() {
+            @Override
+            public TvInputManager createService() {
+                IBinder iBinder = ServiceManager.getService(Context.TV_INPUT_SERVICE);
+                ITvInputManager service = ITvInputManager.Stub.asInterface(iBinder);
+                return new TvInputManager(service, UserHandle.myUserId());
+            }});
+
+        registerService(Context.NETWORK_SCORE_SERVICE, NetworkScoreManager.class,
+                new CachedServiceFetcher<NetworkScoreManager>() {
+            @Override
+            public NetworkScoreManager createService(ContextImpl ctx) {
+                return new NetworkScoreManager(ctx);
+            }});
+
+        registerService(Context.USAGE_STATS_SERVICE, UsageStatsManager.class,
+                new CachedServiceFetcher<UsageStatsManager>() {
+            @Override
+            public UsageStatsManager createService(ContextImpl ctx) {
+                IBinder iBinder = ServiceManager.getService(Context.USAGE_STATS_SERVICE);
+                IUsageStatsManager service = IUsageStatsManager.Stub.asInterface(iBinder);
+                return new UsageStatsManager(ctx.getOuterContext(), service);
+            }});
+
+        registerService(Context.JOB_SCHEDULER_SERVICE, JobScheduler.class,
+                new StaticServiceFetcher<JobScheduler>() {
+            @Override
+            public JobScheduler createService() {
+                IBinder b = ServiceManager.getService(Context.JOB_SCHEDULER_SERVICE);
+                return new JobSchedulerImpl(IJobScheduler.Stub.asInterface(b));
+            }});
+
+        registerService(Context.PERSISTENT_DATA_BLOCK_SERVICE, PersistentDataBlockManager.class,
+                new StaticServiceFetcher<PersistentDataBlockManager>() {
+            @Override
+            public PersistentDataBlockManager createService() {
+                IBinder b = ServiceManager.getService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
+                IPersistentDataBlockService persistentDataBlockService =
+                        IPersistentDataBlockService.Stub.asInterface(b);
+                if (persistentDataBlockService != null) {
+                    return new PersistentDataBlockManager(persistentDataBlockService);
+                } else {
+                    // not supported
+                    return null;
+                }
+            }});
+
+        registerService(Context.MEDIA_PROJECTION_SERVICE, MediaProjectionManager.class,
+                new CachedServiceFetcher<MediaProjectionManager>() {
+            @Override
+            public MediaProjectionManager createService(ContextImpl ctx) {
+                return new MediaProjectionManager(ctx);
+            }});
+
+        registerService(Context.APPWIDGET_SERVICE, AppWidgetManager.class,
+                new CachedServiceFetcher<AppWidgetManager>() {
+            @Override
+            public AppWidgetManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
+                return new AppWidgetManager(ctx, IAppWidgetService.Stub.asInterface(b));
+            }});
+
+        registerService(Context.MIDI_SERVICE, MidiManager.class,
+                new CachedServiceFetcher<MidiManager>() {
+            @Override
+            public MidiManager createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(Context.MIDI_SERVICE);
+                return new MidiManager(ctx, IMidiManager.Stub.asInterface(b));
+            }});
+    }
+
+    /**
+     * Creates an array which is used to cache per-Context service instances.
+     */
+    public static Object[] createServiceCache() {
+        return new Object[sServiceCacheSize];
+    }
+
+    /**
+     * Gets a system service from a given context.
+     */
+    public static Object getSystemService(ContextImpl ctx, String name) {
+        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
+        return fetcher != null ? fetcher.getService(ctx) : null;
+    }
+
+    /**
+     * Gets the name of the system-level service that is represented by the specified class. 
+     */
+    public static String getSystemServiceName(Class<?> serviceClass) {
+        return SYSTEM_SERVICE_NAMES.get(serviceClass);
+    }
+
+    /**
+     * Statically registers a system service with the context.
+     * This method must be called during static initialization only.
+     */
+    private static <T> void registerService(String serviceName, Class<T> serviceClass,
+            ServiceFetcher<T> serviceFetcher) {
+        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
+        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
+    }
+
+    /**
+     * Base interface for classes that fetch services.
+     * These objects must only be created during static initialization.
+     */
+    static abstract interface ServiceFetcher<T> {
+        T getService(ContextImpl ctx);
+    }
+
+    /**
+     * Override this class when the system service constructor needs a
+     * ContextImpl and should be cached and retained by that context.
+     */
+    static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
+        private final int mCacheIndex;
+
+        public CachedServiceFetcher() {
+            mCacheIndex = sServiceCacheSize++;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public final T getService(ContextImpl ctx) {
+            final Object[] cache = ctx.mServiceCache;
+            synchronized (cache) {
+                // Fetch or create the service.
+                Object service = cache[mCacheIndex];
+                if (service == null) {
+                    service = createService(ctx);
+                    cache[mCacheIndex] = service;
+                }
+                return (T)service;
+            }
+        }
+
+        public abstract T createService(ContextImpl ctx);
+    }
+
+    /**
+     * Override this class when the system service does not need a ContextImpl
+     * and should be cached and retained process-wide.
+     */
+    static abstract class StaticServiceFetcher<T> implements ServiceFetcher<T> {
+        private T mCachedInstance;
+
+        @Override
+        public final T getService(ContextImpl unused) {
+            synchronized (StaticServiceFetcher.this) {
+                if (mCachedInstance == null) {
+                    mCachedInstance = createService();
+                }
+                return mCachedInstance;
+            }
+        }
+
+        public abstract T createService();
+    }
+}
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 7f9693f..7b84cb4 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -156,8 +156,8 @@
 
         @Override
         public void deliverCancel(IVoiceInteractorRequest request) throws RemoteException {
-            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(
-                    MSG_CANCEL_RESULT, request));
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOO(
+                    MSG_CANCEL_RESULT, request, null));
         }
     };
 
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 3074b49..d1e40ae 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -165,15 +165,24 @@
     /** @hide */
     public static class PolicyInfo {
         public final int ident;
-        final public String tag;
-        final public int label;
-        final public int description;
+        public final String tag;
+        public final int label;
+        public final int description;
+        public final int labelForSecondaryUsers;
+        public final int descriptionForSecondaryUsers;
 
-        public PolicyInfo(int identIn, String tagIn, int labelIn, int descriptionIn) {
-            ident = identIn;
-            tag = tagIn;
-            label = labelIn;
-            description = descriptionIn;
+        public PolicyInfo(int ident, String tag, int label, int description) {
+            this(ident, tag, label, description, label, description);
+        }
+
+        public PolicyInfo(int ident, String tag, int label, int description,
+                int labelForSecondaryUsers, int descriptionForSecondaryUsers) {
+            this.ident = ident;
+            this.tag = tag;
+            this.label = label;
+            this.description = description;
+            this.labelForSecondaryUsers = labelForSecondaryUsers;
+            this.descriptionForSecondaryUsers = descriptionForSecondaryUsers;
         }
     }
 
@@ -184,7 +193,10 @@
     static {
         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WIPE_DATA, "wipe-data",
                 com.android.internal.R.string.policylab_wipeData,
-                com.android.internal.R.string.policydesc_wipeData));
+                com.android.internal.R.string.policydesc_wipeData,
+                com.android.internal.R.string.policylab_wipeData_secondaryUser,
+                com.android.internal.R.string.policydesc_wipeData_secondaryUser
+                ));
         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_RESET_PASSWORD, "reset-password",
                 com.android.internal.R.string.policylab_resetPassword,
                 com.android.internal.R.string.policydesc_resetPassword));
@@ -193,7 +205,10 @@
                 com.android.internal.R.string.policydesc_limitPassword));
         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_WATCH_LOGIN, "watch-login",
                 com.android.internal.R.string.policylab_watchLogin,
-                com.android.internal.R.string.policydesc_watchLogin));
+                com.android.internal.R.string.policydesc_watchLogin,
+                com.android.internal.R.string.policylab_watchLogin,
+                com.android.internal.R.string.policydesc_watchLogin_secondaryUser
+        ));
         sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_FORCE_LOCK, "force-lock",
                 com.android.internal.R.string.policylab_forceLock,
                 com.android.internal.R.string.policydesc_forceLock));
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d0ebdbd..337bac5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -68,7 +68,7 @@
 /**
  * Public interface for managing policies enforced on a device. Most clients of this class must be
  * registered with the system as a
- * <a href={@docRoot}guide/topics/admin/device-admin.html">device administrator</a>. Additionally,
+ * <a href="{@docRoot}guide/topics/admin/device-admin.html">device administrator</a>. Additionally,
  * a device administrator may be registered as either a profile or device owner. A given method is
  * accessible to all device administrators unless the documentation for that method specifies that
  * it is restricted to either device or profile owners.
@@ -2710,6 +2710,7 @@
      * <p>If {@link #KEYGUARD_DISABLE_TRUST_AGENTS} is set and options is not null for all admins,
      * then it's up to the TrustAgent itself to aggregate the values from all device admins.
      * <p>Consult documentation for the specific TrustAgent to determine legal options parameters.
+     * @hide
      */
     public void setTrustAgentConfiguration(ComponentName admin, ComponentName target,
             PersistableBundle configuration) {
@@ -2735,6 +2736,7 @@
      * for this {@param agent} or calls it with a null configuration, null is returned.
      * @param agent Which component to get enabled features for.
      * @return configuration for the given trust agent.
+     * @hide
      */
     public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin,
             ComponentName agent) {
@@ -3305,7 +3307,8 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      *
      * @see Activity#startLockTask()
-     * @see DeviceAdminReceiver#onLockTaskModeChanged(Context, Intent, boolean, String)
+     * @see DeviceAdminReceiver#onLockTaskModeEntering(Context, Intent, String)
+     * @see DeviceAdminReceiver#onLockTaskModeExiting(Context, Intent)
      * @see UserManager#DISALLOW_CREATE_WINDOWS
      */
     public void setLockTaskPackages(ComponentName admin, String[] packages)
@@ -3360,13 +3363,18 @@
      * <li>{@link Settings.Global#ADB_ENABLED}</li>
      * <li>{@link Settings.Global#AUTO_TIME}</li>
      * <li>{@link Settings.Global#AUTO_TIME_ZONE}</li>
-     * <li>{@link Settings.Global#BLUETOOTH_ON}</li>
+     * <li>{@link Settings.Global#BLUETOOTH_ON}
+     * Changing this setting has not effect as of {@link android.os.Build.VERSION_CODES#MNC}. Use
+     * {@link android.bluetooth.BluetoothAdapter#enable()} and
+     * {@link android.bluetooth.BluetoothAdapter#disable()} instead.</li>
      * <li>{@link Settings.Global#DATA_ROAMING}</li>
      * <li>{@link Settings.Global#DEVELOPMENT_SETTINGS_ENABLED}</li>
      * <li>{@link Settings.Global#MODE_RINGER}</li>
      * <li>{@link Settings.Global#NETWORK_PREFERENCE}</li>
      * <li>{@link Settings.Global#USB_MASS_STORAGE_ENABLED}</li>
-     * <li>{@link Settings.Global#WIFI_ON}</li>
+     * <li>{@link Settings.Global#WIFI_ON}
+     * Changing this setting has not effect as of {@link android.os.Build.VERSION_CODES#MNC}. Use
+     * {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} instead.</li>
      * <li>{@link Settings.Global#WIFI_SLEEP_POLICY}</li>
      * </ul>
      *
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 46ccc95..010c860 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -36,7 +36,6 @@
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
-import android.media.MediaScannerConnection.OnScanCompletedListener;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Environment;
@@ -469,10 +468,10 @@
 
     /**
      * Retrieve styled attribute information in this Context's theme.  See
-     * {@link Resources.Theme#obtainStyledAttributes(int[])}
+     * {@link android.content.res.Resources.Theme#obtainStyledAttributes(int[])}
      * for more information.
      *
-     * @see Resources.Theme#obtainStyledAttributes(int[])
+     * @see android.content.res.Resources.Theme#obtainStyledAttributes(int[])
      */
     public final TypedArray obtainStyledAttributes(
             int[] attrs) {
@@ -481,10 +480,10 @@
 
     /**
      * Retrieve styled attribute information in this Context's theme.  See
-     * {@link Resources.Theme#obtainStyledAttributes(int, int[])}
+     * {@link android.content.res.Resources.Theme#obtainStyledAttributes(int, int[])}
      * for more information.
      *
-     * @see Resources.Theme#obtainStyledAttributes(int, int[])
+     * @see android.content.res.Resources.Theme#obtainStyledAttributes(int, int[])
      */
     public final TypedArray obtainStyledAttributes(
             @StyleableRes int resid, int[] attrs) throws Resources.NotFoundException {
@@ -493,10 +492,10 @@
 
     /**
      * Retrieve styled attribute information in this Context's theme.  See
-     * {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
+     * {@link android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
      * for more information.
      *
-     * @see Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
+     * @see android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
      */
     public final TypedArray obtainStyledAttributes(
             AttributeSet set, int[] attrs) {
@@ -505,10 +504,10 @@
 
     /**
      * Retrieve styled attribute information in this Context's theme.  See
-     * {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
+     * {@link android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)}
      * for more information.
      *
-     * @see Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
+     * @see android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
      */
     public final TypedArray obtainStyledAttributes(
             AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
@@ -753,7 +752,8 @@
      * are not automatically scanned by the media scanner, you can explicitly
      * add them to the media database with
      * {@link android.media.MediaScannerConnection#scanFile(Context, String[], String[],
-     *      OnScanCompletedListener) MediaScannerConnection.scanFile}.
+     *      android.media.MediaScannerConnection.OnScanCompletedListener)
+     *      MediaScannerConnection.scanFile}.
      * Note that this is not the same as
      * {@link android.os.Environment#getExternalStoragePublicDirectory
      * Environment.getExternalStoragePublicDirectory()}, which provides
@@ -1918,7 +1918,7 @@
      * @return The first sticky intent found that matches <var>filter</var>,
      *         or null if there are none.
      *
-     * @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler
+     * @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
      * @see #sendBroadcast
      * @see #unregisterReceiver
      */
@@ -2081,7 +2081,9 @@
      * @hide
      */
     @SystemApi
-    public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags, UserHandle user) {
+    @SuppressWarnings("unused")
+    public boolean bindServiceAsUser(Intent service, ServiceConnection conn,
+            int flags, UserHandle user) {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 
@@ -2316,6 +2318,51 @@
     public abstract Object getSystemService(@ServiceName @NonNull String name);
 
     /**
+     * Return the handle to a system-level service by class.
+     * <p>
+     * Currently available classes are:
+     * {@link android.view.WindowManager}, {@link android.view.LayoutInflater},
+     * {@link android.app.ActivityManager}, {@link android.os.PowerManager},
+     * {@link android.app.AlarmManager}, {@link android.app.NotificationManager},
+     * {@link android.app.KeyguardManager}, {@link android.location.LocationManager},
+     * {@link android.app.SearchManager}, {@link android.os.Vibrator},
+     * {@link android.net.ConnectivityManager},
+     * {@link android.net.wifi.WifiManager},
+     * {@link android.media.AudioManager}, {@link android.media.MediaRouter},
+     * {@link android.telephony.TelephonyManager}, {@link android.telephony.SubscriptionManager},
+     * {@link android.view.inputmethod.InputMethodManager},
+     * {@link android.app.UiModeManager}, {@link android.app.DownloadManager},
+     * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler}.
+     * </p><p>
+     * Note: System services obtained via this API may be closely associated with
+     * the Context in which they are obtained from.  In general, do not share the
+     * service objects between various different contexts (Activities, Applications,
+     * Services, Providers, etc.)
+     * </p>
+     *
+     * @param serviceClass The class of the desired service.
+     * @return The service or null if the class is not a supported system service.
+     */
+    @SuppressWarnings("unchecked")
+    public final <T> T getSystemService(Class<T> serviceClass) {
+        // Because subclasses may override getSystemService(String) we cannot
+        // perform a lookup by class alone.  We must first map the class to its
+        // service name then invoke the string-based method.
+        String serviceName = getSystemServiceName(serviceClass);
+        return serviceName != null ? (T)getSystemService(serviceName) : null;
+    }
+
+    /**
+     * Gets the name of the system-level service that is represented by the specified class.
+     *
+     * @param serviceClass The class of the desired service.
+     * @return The service name or null if the class is not a supported system service.
+     *
+     * @hide
+     */
+    public abstract String getSystemServiceName(Class<?> serviceClass);
+
+    /**
      * Use with {@link #getSystemService} to retrieve a
      * {@link android.os.PowerManager} for controlling power management,
      * including "wake locks," which let you keep the device on while
@@ -2610,7 +2657,7 @@
      * of fingerprints.
      *
      * @see #getSystemService
-     * @see android.app.FingerprintManager
+     * @see android.service.fingerprint.FingerprintManager
      * @hide
      */
     public static final String FINGERPRINT_SERVICE = "fingerprint";
@@ -2666,11 +2713,11 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
-     * {@link android.text.ClipboardManager} for accessing and modifying
+     * {@link android.content.ClipboardManager} for accessing and modifying
      * the contents of the global clipboard.
      *
      * @see #getSystemService
-     * @see android.text.ClipboardManager
+     * @see android.content.ClipboardManager
      */
     public static final String CLIPBOARD_SERVICE = "clipboard";
 
@@ -2965,7 +3012,7 @@
      * android.media.projection.MediaProjectionManager} instance for managing
      * media projection sessions.
      * @see #getSystemService
-     * @see android.media.projection.ProjectionManager
+     * @see android.media.projection.MediaProjectionManager
      */
     public static final String MEDIA_PROJECTION_SERVICE = "media_projection";
 
@@ -3401,7 +3448,7 @@
      * are not shared, however they share common state (Resources, ClassLoader,
      * etc) so the Context instance itself is fairly lightweight.
      *
-     * <p>Throws {@link PackageManager.NameNotFoundException} if there is no
+     * <p>Throws {@link android.content.pm.PackageManager.NameNotFoundException} if there is no
      * application with the given package name.
      *
      * <p>Throws {@link java.lang.SecurityException} if the Context requested
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index cfae1cf..6e8b7c1 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -284,36 +284,43 @@
     }
 
     @Override
+    @Deprecated
     public Drawable getWallpaper() {
         return mBase.getWallpaper();
     }
 
     @Override
+    @Deprecated
     public Drawable peekWallpaper() {
         return mBase.peekWallpaper();
     }
 
     @Override
+    @Deprecated
     public int getWallpaperDesiredMinimumWidth() {
         return mBase.getWallpaperDesiredMinimumWidth();
     }
 
     @Override
+    @Deprecated
     public int getWallpaperDesiredMinimumHeight() {
         return mBase.getWallpaperDesiredMinimumHeight();
     }
 
     @Override
+    @Deprecated
     public void setWallpaper(Bitmap bitmap) throws IOException {
         mBase.setWallpaper(bitmap);
     }
 
     @Override
+    @Deprecated
     public void setWallpaper(InputStream data) throws IOException {
         mBase.setWallpaper(data);
     }
 
     @Override
+    @Deprecated
     public void clearWallpaper() throws IOException {
         mBase.clearWallpaper();
     }
@@ -445,11 +452,13 @@
     }
 
     @Override
+    @Deprecated
     public void sendStickyBroadcast(Intent intent) {
         mBase.sendStickyBroadcast(intent);
     }
 
     @Override
+    @Deprecated
     public void sendStickyOrderedBroadcast(
         Intent intent, BroadcastReceiver resultReceiver,
         Handler scheduler, int initialCode, String initialData,
@@ -460,16 +469,19 @@
     }
 
     @Override
+    @Deprecated
     public void removeStickyBroadcast(Intent intent) {
         mBase.removeStickyBroadcast(intent);
     }
 
     @Override
+    @Deprecated
     public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
         mBase.sendStickyBroadcastAsUser(intent, user);
     }
 
     @Override
+    @Deprecated
     public void sendStickyOrderedBroadcastAsUser(Intent intent,
             UserHandle user, BroadcastReceiver resultReceiver,
             Handler scheduler, int initialCode, String initialData,
@@ -479,6 +491,7 @@
     }
 
     @Override
+    @Deprecated
     public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
         mBase.removeStickyBroadcastAsUser(intent, user);
     }
@@ -563,6 +576,11 @@
     }
 
     @Override
+    public String getSystemServiceName(Class<?> serviceClass) {
+        return mBase.getSystemServiceName(serviceClass);
+    }
+
+    @Override
     public int checkPermission(String permission, int pid, int uid) {
         return mBase.checkPermission(permission, pid, uid);
     }
@@ -679,6 +697,7 @@
     }
 
     /** @hide */
+    @Override
     public Context createApplicationContext(ApplicationInfo application,
             int flags) throws PackageManager.NameNotFoundException {
         return mBase.createApplicationContext(application, flags);
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index e822708..e1a2aa9 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -881,6 +881,13 @@
     /**
      * @hide
      */
+    public boolean isForwardLocked() {
+        return (privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
+    }
+
+    /**
+     * @hide
+     */
     @Override protected ApplicationInfo getApplicationInfo() {
         return this;
     }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b0e0300..1140756 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -4405,6 +4405,13 @@
             return false;
         }
 
+        /**
+         * @hide
+         */
+        public boolean isForwardLocked() {
+            return applicationInfo.isForwardLocked();
+        }
+
         public String toString() {
             return "Package{"
                 + Integer.toHexString(System.identityHashCode(this))
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index bb162153..adab9be 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -132,6 +132,19 @@
             float requestedRefreshRate, boolean inTraversal);
 
     /**
+     * Applies an offset to the contents of a display, for example to avoid burn-in.
+     * <p>
+     * TODO: Technically this should be associated with a physical rather than logical
+     * display but this is good enough for now.
+     * </p>
+     *
+     * @param displayId The logical display id to update.
+     * @param x The X offset by which to shift the contents of the display.
+     * @param y The Y offset by which to shift the contents of the display.
+     */
+    public abstract void setDisplayOffsets(int displayId, int x, int y);
+
+    /**
      * Describes the requested power state of the display.
      *
      * This object is intended to describe the general characteristics of the
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 537e993..bd5a3922 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -162,7 +162,15 @@
      */
     public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5;
 
-    private IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
+    private final IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
+
+    /**
+     * @removed Was previously made visible by accident.
+     */
+    public BatteryManager() {
+        mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(
+                ServiceManager.getService("batteryproperties"));
+    }
 
     /**
      * Query a battery property from the batteryproperties service.
@@ -174,12 +182,7 @@
         long ret;
 
         if (mBatteryPropertiesRegistrar == null) {
-            IBinder b = ServiceManager.getService("batteryproperties");
-            mBatteryPropertiesRegistrar =
-                IBatteryPropertiesRegistrar.Stub.asInterface(b);
-
-            if (mBatteryPropertiesRegistrar == null)
-                return Long.MIN_VALUE;
+            return Long.MIN_VALUE;
         }
 
         try {
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index a8c0c4c..797457a 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -23,6 +23,8 @@
  * @hide
  */
 oneway interface IVoiceInteractionSession {
+    void show(in Bundle sessionArgs, int flags);
+    void hide();
     void handleAssist(in Bundle assistData);
     void taskStarted(in Intent intent, int taskId);
     void taskFinished(in Intent intent, int taskId);
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 54a3a0a..0c01b25 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -71,7 +71,7 @@
     public static final String SERVICE_META_DATA = "android.voice_interaction";
 
     /**
-     * Flag for use with {@link #startSession}: request that the session be started with
+     * Flag for use with {@link #showSession: request that the session be started with
      * assist data from the currently focused activity.
      */
     public static final int START_WITH_ASSIST = 1<<0;
@@ -139,20 +139,25 @@
     }
 
     /**
-     * Initiate the execution of a new {@link android.service.voice.VoiceInteractionSession}.
+     * Request that the associated {@link android.service.voice.VoiceInteractionSession} be
+     * shown to the user, starting it if necessary.
      * @param args Arbitrary arguments that will be propagated to the session.
      */
-    public void startSession(Bundle args, int flags) {
+    public void showSession(Bundle args, int flags) {
         if (mSystemService == null) {
             throw new IllegalStateException("Not available until onReady() is called");
         }
         try {
-            mSystemService.startSession(mInterface, args, flags);
+            mSystemService.showSession(mInterface, args, flags);
         } catch (RemoteException e) {
         }
     }
 
     /** @hide */
+    public void startSession(Bundle args, int flags) {
+        showSession(args, flags);
+    }
+    /** @hide */
     public void startSession(Bundle args) {
         startSession(args, 0);
     }
@@ -174,7 +179,7 @@
     /**
      * Called during service initialization to tell you when the system is ready
      * to receive interaction from it. You should generally do initialization here
-     * rather than in {@link #onCreate}. Methods such as {@link #startSession} and
+     * rather than in {@link #onCreate}. Methods such as {@link #showSession} and
      * {@link #createAlwaysOnHotwordDetector}
      * will not be operational until this point.
      */
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index a3a2ca1..4cf0e4c 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -53,10 +53,9 @@
 
 /**
  * An active voice interaction session, providing a facility for the implementation
- * to interact with the user in the voice interaction layer.  This interface is no shown
- * by default, but you can request that it be shown with {@link #showWindow()}, which
- * will result in a later call to {@link #onCreateContentView()} in which the UI can be
- * built
+ * to interact with the user in the voice interaction layer.  The user interface is
+ * initially shown by default, and can be created be overriding {@link #onCreateContentView()}
+ * in which the UI can be built.
  *
  * <p>A voice interaction session can be self-contained, ultimately calling {@link #finish}
  * when done.  It can also initiate voice interactions with applications by calling
@@ -151,6 +150,17 @@
 
     final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
         @Override
+        public void show(Bundle sessionArgs, int flags) {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_SHOW,
+                    flags, sessionArgs));
+        }
+
+        @Override
+        public void hide() {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_HIDE));
+        }
+
+        @Override
         public void handleAssist(Bundle assistBundle) {
             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_HANDLE_ASSIST,
                     assistBundle));
@@ -284,6 +294,8 @@
     static final int MSG_CLOSE_SYSTEM_DIALOGS = 102;
     static final int MSG_DESTROY = 103;
     static final int MSG_HANDLE_ASSIST = 104;
+    static final int MSG_SHOW = 105;
+    static final int MSG_HIDE = 106;
 
     class MyCallbacks implements HandlerCaller.Callback, SoftInputWindow.Callback {
         @Override
@@ -324,9 +336,8 @@
                     args.arg1 = onGetSupportedCommands((Caller) args.arg1, (String[]) args.arg2);
                     break;
                 case MSG_CANCEL:
-                    args = (SomeArgs)msg.obj;
-                    if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request) args.arg1).mInterface);
-                    onCancel((Request)args.arg1);
+                    if (DEBUG) Log.d(TAG, "onCancel: req=" + ((Request)msg.obj));
+                    onCancel((Request)msg.obj);
                     break;
                 case MSG_TASK_STARTED:
                     if (DEBUG) Log.d(TAG, "onTaskStarted: intent=" + msg.obj
@@ -350,6 +361,15 @@
                     if (DEBUG) Log.d(TAG, "onHandleAssist: " + (Bundle)msg.obj);
                     onHandleAssist((Bundle) msg.obj);
                     break;
+                case MSG_SHOW:
+                    if (DEBUG) Log.d(TAG, "doShow: args=" + msg.obj
+                            + " flags=" + msg.arg1);
+                    doShow((Bundle) msg.obj, msg.arg1);
+                    break;
+                case MSG_HIDE:
+                    if (DEBUG) Log.d(TAG, "doHide");
+                    doHide();
+                    break;
             }
         }
 
@@ -457,6 +477,45 @@
         onCreate(args, startFlags);
     }
 
+    void doShow(Bundle args, int flags) {
+        if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
+                + " mWindowVisible=" + mWindowVisible);
+
+        if (mInShowWindow) {
+            Log.w(TAG, "Re-entrance in to showWindow");
+            return;
+        }
+
+        try {
+            mInShowWindow = true;
+            if (!mWindowVisible) {
+                if (!mWindowAdded) {
+                    mWindowAdded = true;
+                    View v = onCreateContentView();
+                    if (v != null) {
+                        setContentView(v);
+                    }
+                }
+            }
+            onShow(args, flags);
+            if (!mWindowVisible) {
+                mWindowVisible = true;
+                mWindow.show();
+            }
+        } finally {
+            mWindowWasVisible = true;
+            mInShowWindow = false;
+        }
+    }
+
+    void doHide() {
+        if (mWindowVisible) {
+            mWindow.hide();
+            mWindowVisible = false;
+            onHide();
+        }
+    }
+
     void doDestroy() {
         onDestroy();
         if (mInitialized) {
@@ -484,41 +543,28 @@
         mContentFrame = (FrameLayout)mRootView.findViewById(android.R.id.content);
     }
 
-    public void showWindow() {
-        if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
-                + " mWindowVisible=" + mWindowVisible);
-
-        if (mInShowWindow) {
-            Log.w(TAG, "Re-entrance in to showWindow");
-            return;
-        }
-
+    public void show() {
         try {
-            mInShowWindow = true;
-            if (!mWindowVisible) {
-                mWindowVisible = true;
-                if (!mWindowAdded) {
-                    mWindowAdded = true;
-                    View v = onCreateContentView();
-                    if (v != null) {
-                        setContentView(v);
-                    }
-                }
-                mWindow.show();
-            }
-        } finally {
-            mWindowWasVisible = true;
-            mInShowWindow = false;
+            mSystemService.showSessionFromSession(mToken, null, 0);
+        } catch (RemoteException e) {
         }
     }
 
-    public void hideWindow() {
-        if (mWindowVisible) {
-            mWindow.hide();
-            mWindowVisible = false;
+    public void hide() {
+        try {
+            mSystemService.hideSessionFromSession(mToken);
+        } catch (RemoteException e) {
         }
     }
 
+    /** TODO: remove */
+    public void showWindow() {
+    }
+
+    /** TODO: remove */
+    public void hideWindow() {
+    }
+
     /**
      * You can call this to customize the theme used by your IME's window.
      * This must be set before {@link #onCreate}, so you
@@ -611,15 +657,33 @@
     }
 
     /**
-     * Initiatize a new session.
+     * Initiatize a new session.  The given args and showFlags are the initial values
+     * passed to {@link VoiceInteractionService#showSession VoiceInteractionService.showSession},
+     * if possible.  Normally you should handle these in {@link #onShow}.
+     */
+    public void onCreate(Bundle args, int showFlags) {
+        onCreate(args);
+    }
+
+    /**
+     * Called when the session UI is going to be shown.  This is called after
+     * {@link #onCreateContentView} (if the session's content UI needed to be created) and
+     * immediately prior to the window being shown.  This may be called while the window
+     * is already shown, if a show request has come in while it is shown, to allow you to
+     * update the UI to match the new show arguments.
      *
      * @param args The arguments that were supplied to
-     * {@link VoiceInteractionService#startSession VoiceInteractionService.startSession}.
-     * @param startFlags The start flags originally provided to
-     * {@link VoiceInteractionService#startSession VoiceInteractionService.startSession}.
+     * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
+     * @param showFlags The show flags originally provided to
+     * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
      */
-    public void onCreate(Bundle args, int startFlags) {
-        onCreate(args);
+    public void onShow(Bundle args, int showFlags) {
+    }
+
+    /**
+     * Called immediately after stopping to show the session UI.
+     */
+    public void onHide() {
     }
 
     /**
@@ -663,7 +727,7 @@
     }
 
     public void onBackPressed() {
-        finish();
+        hide();
     }
 
     /**
@@ -672,7 +736,7 @@
      * calls {@link #finish}.
      */
     public void onCloseSystemDialogs() {
-        finish();
+        hide();
     }
 
     /**
@@ -717,7 +781,7 @@
      * @param taskId Unique ID of the finished task.
      */
     public void onTaskFinished(Intent intent, int taskId) {
-        finish();
+        hide();
     }
 
     /**
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index c1341e1..8e9eb48 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -78,7 +78,10 @@
 
     /**
      *  Bit field indicating that street addresses should be matched in methods that
-     *  take an options mask
+     *  take an options mask. Note that this uses the
+     *  {@link android.webkit.WebView#findAddress(String) findAddress()} method in
+     *  {@link android.webkit.WebView} for finding addresses, which has various
+     *  limitations.
      */
     public static final int MAP_ADDRESSES = 0x08;
 
diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
index 54a0025..0814101 100644
--- a/core/java/android/view/PhoneWindow.java
+++ b/core/java/android/view/PhoneWindow.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2006 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -4171,12 +4172,6 @@
         return mMediaController;
     }
 
-    private boolean isTranslucent() {
-        TypedArray a = getWindowStyle();
-        return a.getBoolean(a.getResourceId(
-                R.styleable.Window_windowIsTranslucent, 0), false);
-    }
-
     @Override
     public void setEnterTransition(Transition enterTransition) {
         mEnterTransition = enterTransition;
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 84f0ee5..22e079c 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -34,10 +34,13 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 
 /**
- * An extension to TextView that supports the {@link android.widget.Checkable} interface.
- * This is useful when used in a {@link android.widget.ListView ListView} where the it's 
- * {@link android.widget.ListView#setChoiceMode(int) setChoiceMode} has been set to
- * something other than {@link android.widget.ListView#CHOICE_MODE_NONE CHOICE_MODE_NONE}.
+ * An extension to {@link TextView} that supports the {@link Checkable}
+ * interface and displays.
+ * <p>
+ * This is useful when used in a {@link android.widget.ListView ListView} where
+ * the {@link android.widget.ListView#setChoiceMode(int) setChoiceMode} has
+ * been set to something other than
+ * {@link android.widget.ListView#CHOICE_MODE_NONE CHOICE_MODE_NONE}.
  *
  * @attr ref android.R.styleable#CheckedTextView_checked
  * @attr ref android.R.styleable#CheckedTextView_checkMark
@@ -116,9 +119,10 @@
     }
 
     /**
-     * <p>Changes the checked state of this text view.</p>
+     * Sets the checked state of this view.
      *
-     * @param checked true to check the text, false to uncheck it
+     * @param checked {@code true} set the state to checked, {@code false} to
+     *                uncheck
      */
     public void setChecked(boolean checked) {
         if (mChecked != checked) {
@@ -129,24 +133,24 @@
         }
     }
 
-
     /**
-     * Set the checkmark to a given Drawable, identified by its resourece id. This will be drawn
-     * when {@link #isChecked()} is true.
+     * Sets the check mark to the drawable with the specified resource ID.
+     * <p>
+     * When this view is checked, the drawable's state set will include
+     * {@link android.R.attr#state_checked}.
      *
-     * @param resid The Drawable to use for the checkmark.
-     *
+     * @param resId the resource identifier of drawable to use as the check
+     *              mark
+     * @attr ref android.R.styleable#CheckedTextView_checkMark
      * @see #setCheckMarkDrawable(Drawable)
      * @see #getCheckMarkDrawable()
-     *
-     * @attr ref android.R.styleable#CheckedTextView_checkMark
      */
-    public void setCheckMarkDrawable(@DrawableRes int resid) {
-        if (resid != 0 && resid == mCheckMarkResource) {
+    public void setCheckMarkDrawable(@DrawableRes int resId) {
+        if (resId != 0 && resId == mCheckMarkResource) {
             return;
         }
 
-        mCheckMarkResource = resid;
+        mCheckMarkResource = resId;
 
         Drawable d = null;
         if (mCheckMarkResource != 0) {
@@ -156,14 +160,15 @@
     }
 
     /**
-     * Set the checkmark to a given Drawable. This will be drawn when {@link #isChecked()} is true.
+     * Set the check mark to the specified drawable.
+     * <p>
+     * When this view is checked, the drawable's state set will include
+     * {@link android.R.attr#state_checked}.
      *
-     * @param d The Drawable to use for the checkmark.
-     *
+     * @param d the drawable to use for the check mark
+     * @attr ref android.R.styleable#CheckedTextView_checkMark
      * @see #setCheckMarkDrawable(int)
      * @see #getCheckMarkDrawable()
-     *
-     * @attr ref android.R.styleable#CheckedTextView_checkMark
      */
     public void setCheckMarkDrawable(Drawable d) {
         if (mCheckMarkDrawable != null) {
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
old mode 100644
new mode 100755
index a053901..42bc7f2
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -112,8 +112,8 @@
         mTempDate = getCalendarForLocale(mMaxDate, locale);
         mCurrentDate = getCalendarForLocale(mCurrentDate, locale);
 
-        mMinDate.set(DEFAULT_START_YEAR, 1, 1);
-        mMaxDate.set(DEFAULT_END_YEAR, 12, 31);
+        mMinDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1);
+        mMaxDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31);
 
         final Resources res = mDelegator.getResources();
         final TypedArray a = mContext.obtainStyledAttributes(attrs,
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 6d90420..8f549a6 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -26,9 +26,11 @@
 import android.service.voice.IVoiceInteractionSession;
 
 interface IVoiceInteractionManagerService {
-    void startSession(IVoiceInteractionService service, in Bundle sessionArgs, int flags);
+    void showSession(IVoiceInteractionService service, in Bundle sessionArgs, int flags);
     boolean deliverNewSession(IBinder token, IVoiceInteractionSession session,
             IVoiceInteractor interactor);
+    boolean showSessionFromSession(IBinder token, in Bundle sessionArgs, int flags);
+    boolean hideSessionFromSession(IBinder token);
     int startVoiceActivity(IBinder token, in Intent intent, String resolvedType);
     void finish(IBinder token);
 
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index d617c05..89990c2 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -19,6 +19,7 @@
 import android.animation.TimeInterpolator;
 import android.app.Activity;
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -38,6 +39,7 @@
     private static final String TAG = "SwipeDismissLayout";
 
     private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .33f;
+    private boolean mUseDynamicTranslucency = true;
 
     public interface OnDismissedListener {
         void onDismissed(SwipeDismissLayout layout);
@@ -85,7 +87,7 @@
                     // and temporarily disables translucency when it is fully visible.
                     // As soon as the user starts swiping, we will re-enable
                     // translucency.
-                    if (getContext() instanceof Activity) {
+                    if (mUseDynamicTranslucency && getContext() instanceof Activity) {
                         ((Activity) getContext()).convertFromTranslucent();
                     }
                 }
@@ -117,6 +119,11 @@
                 android.R.integer.config_shortAnimTime);
         mCancelInterpolator = new DecelerateInterpolator(1.5f);
         mDismissInterpolator = new AccelerateInterpolator(1.5f);
+        TypedArray a = context.getTheme().obtainStyledAttributes(
+                com.android.internal.R.styleable.Theme);
+        mUseDynamicTranslucency = !a.hasValue(
+                com.android.internal.R.styleable.Window_windowIsTranslucent);
+        a.recycle();
     }
 
     public void setOnDismissedListener(OnDismissedListener listener) {
@@ -230,7 +237,7 @@
                 mLastX = ev.getRawX();
                 updateSwiping(ev);
                 if (mSwiping) {
-                    if (getContext() instanceof Activity) {
+                    if (mUseDynamicTranslucency && getContext() instanceof Activity) {
                         ((Activity) getContext()).convertToTranslucent(null, null);
                     }
                     setProgress(ev.getRawX() - mDownX);
@@ -254,7 +261,7 @@
     }
 
     protected void cancel() {
-        if (getContext() instanceof Activity) {
+        if (mUseDynamicTranslucency && getContext() instanceof Activity) {
             ((Activity) getContext()).convertFromTranslucent();
         }
         if (mProgressListener != null) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 1dd10e1..28f1a3a 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -5,7 +5,7 @@
 LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
 LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
 LOCAL_CFLAGS += -U__APPLE__
-LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast
+LOCAL_CFLAGS += -Wno-unused-parameter
 LOCAL_CFLAGS += -Wno-non-virtual-dtor
 LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
 LOCAL_CPPFLAGS += -Wno-conversion-null
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 1afcf73..36f7963 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -160,7 +160,8 @@
 android_eglGetDisplayInt
   (JNIEnv *_env, jobject _this, jint display_id) {
 
-    if ((EGLNativeDisplayType)display_id != EGL_DEFAULT_DISPLAY) {
+    if (static_cast<uintptr_t>(display_id) !=
+        reinterpret_cast<uintptr_t>(EGL_DEFAULT_DISPLAY)) {
         jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglGetDisplay");
         return 0;
     }
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index 713fff9..226162d 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -1935,7 +1935,11 @@
         (GLsizei *)length,
         (GLint *)size,
         (GLenum *)type,
-        (char *)name
+        // The cast below is incorrect. The driver will end up writing to the
+        // address specified by name, which will always crash the process since
+        // it is guaranteed to be in low memory. The additional static_cast
+        // suppresses the warning for now. http://b/19478262
+        (char *)static_cast<uintptr_t>(name)
     );
     if (_typeArray) {
         releasePointer(_env, _typeArray, type, JNI_TRUE);
@@ -3643,7 +3647,7 @@
         (GLenum)mode,
         (GLsizei)count,
         (GLenum)type,
-        (GLvoid *)indicesOffset,
+        (GLvoid *)static_cast<uintptr_t>(indicesOffset),
         (GLsizei)instanceCount
     );
 }
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 2df13b7..6c95b8a 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -159,7 +159,7 @@
     }
 
     struct logger_list *logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, O_RDONLY | O_NONBLOCK, 0, 0);
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, 0);
 
     if (!logger_list) {
         jniThrowIOException(env, errno);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6094fd1..4b97138 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -300,6 +300,8 @@
     <protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_DONE" />
     <protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED" />
 
+    <protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" />
+
     <!-- ====================================== -->
     <!-- Permissions for things that cost money -->
     <!-- ====================================== -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6bb61a2..09103e3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -329,7 +329,9 @@
         <attr name="windowOverscan" format="boolean" />
         <!-- Flag indicating whether this is a floating window. -->
         <attr name="windowIsFloating" format="boolean" />
-        <!-- Flag indicating whether this is a translucent window. -->
+        <!-- Flag indicating whether this is a translucent window. If this attribute is unset (but
+             not if set to false), the window might still be considered translucent, if
+             windowSwipeToDismiss is set to true. -->
         <attr name="windowIsTranslucent" format="boolean" />
         <!-- Flag indicating that this window's background should be the
              user's current wallpaper.  Corresponds
@@ -455,7 +457,9 @@
         <attr name="windowTranslucentNavigation" format="boolean" />
 
         <!-- Flag to indicate that a window can be swiped away to be dismissed.
-             Corresponds to {@link android.view.Window#FEATURE_SWIPE_TO_DISMISS} -->
+             Corresponds to {@link android.view.Window#FEATURE_SWIPE_TO_DISMISS}. It will also
+             dynamically change translucency of the window, if the windowIsTranslucent is not set.
+             If windowIsTranslucent is set (to either true or false) it will obey that setting. -->
         <attr name="windowSwipeToDismiss" format="boolean" />
 
         <!-- Flag indicating whether this window requests that content changes be performed
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4c0520e..fd8b803 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2074,4 +2074,23 @@
     <!-- Scale factor threshold used by the screen magnifier to determine when to switch from
          panning to scaling the magnification viewport. -->
     <item name="config_screen_magnification_scaling_threshold" format="float" type="dimen">0.3</item>
+
+    <!-- If true, the display will be shifted around in ambient mode. -->
+    <bool name="config_enableBurnInProtection">false</bool>
+
+    <!-- Specifies the maximum burn-in offset displacement from the center. If -1, no maximum value
+         will be used. -->
+    <integer name="config_burnInProtectionMaxRadius">-1</integer>
+
+    <!-- Specifies the minimum burn-in offset horizontally. -->
+    <integer name="config_burnInProtectionMinHorizontalOffset">0</integer>
+
+    <!-- Specifies the maximum burn-in offset horizontally. -->
+    <integer name="config_burnInProtectionMaxHorizontalOffset">0</integer>
+
+    <!-- Specifies the minimum burn-in offset vertically. -->
+    <integer name="config_burnInProtectionMinVerticalOffset">0</integer>
+
+    <!-- Specifies the maximum burn-in offset vertically. -->
+    <integer name="config_burnInProtectionMaxVerticalOffset">0</integer>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index af4922f..46e3d75 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2634,6 +2634,7 @@
   <public type="style" name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" />
   <public type="style" name="Theme.Material.DayNight.Panel" />
   <public type="style" name="Theme.Material.Light.LightStatusBar" />
+  <public type="style" name="ThemeOverlay.Material.Dialog" />
 
   <!-- Context menu ID for the "Undo" menu item to undo the last text edit operation. -->
   <public type="id" name="undo" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d95b17e..199b783 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2396,7 +2396,7 @@
     <!-- Title of policy access to limiting the user's password choices -->
     <string name="policylab_limitPassword">Set password rules</string>
     <!-- Description of policy access to limiting the user's password choices -->
-    <string name="policydesc_limitPassword">Control the length and the characters allowed in screen-unlock passwords.</string>
+    <string name="policydesc_limitPassword">Control the length and the characters allowed in screen lock passwords and PINs.</string>
     <!-- Title of policy access to watch user login attempts -->
     <string name="policylab_watchLogin">Monitor screen-unlock attempts</string>
     <!-- Description of policy access to watch user login attempts -->
@@ -2411,15 +2411,24 @@
     <string name="policydesc_watchLogin" product="default">Monitor the number of incorrect passwords
     typed. when unlocking the screen, and lock the phone or erase all the phone\'s
     data if too many incorrect passwords are typed.</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock the tablet or erase all this user\'s data
+    if too many incorrect passwords are typed.</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="TV">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock the TV or erase all this user\'s data
+    if too many incorrect passwords are typed.</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default">Monitor the number of incorrect passwords
+    typed when unlocking the screen, and lock the phone or erase all this user\'s data
+    if too many incorrect passwords are typed.</string>
     <!-- Title of policy access to reset user's password -->
-    <string name="policylab_resetPassword">Change the screen-unlock password</string>
+    <string name="policylab_resetPassword">Change the screen lock</string>
     <!-- Description of policy access to reset user's password -->
-    <string name="policydesc_resetPassword">Change the screen-unlock password.</string>
+    <string name="policydesc_resetPassword">Change the screen lock.</string>
     <!-- Title of policy access to force lock the device -->
     <string name="policylab_forceLock">Lock the screen</string>
     <!-- Description of policy access to limiting the user's password choices -->
     <string name="policydesc_forceLock">Control how and when the screen locks.</string>
-    <!-- Title of policy access to wipe the user's data -->
+    <!-- Title of policy access to wipe primary user's data -->
     <string name="policylab_wipeData">Erase all data</string>
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData" product="tablet">Erase the tablet\'s data without warning by performing a factory data reset.</string>
@@ -2427,15 +2436,23 @@
     <string name="policydesc_wipeData" product="tv">Erase the TV\'s data without warning by performing a factory data reset.</string>
     <!-- Description of policy access to wipe the user's data -->
     <string name="policydesc_wipeData" product="default">Erase the phone\'s data without warning by performing a factory data reset.</string>
-    <string name="policylab_setGlobalProxy">Set the device global proxy</string>
+    <!-- Title of policy access to wipe secondary user's data -->
+    <string name="policylab_wipeData_secondaryUser">Erase user data</string>
     <!-- Description of policy access to wipe the user's data -->
+    <string name="policydesc_wipeData_secondaryUser" product="tablet">Erase this user\'s data on this tablet without warning.</string>
+    <!-- Description of policy access to wipe the user's data -->
+    <string name="policydesc_wipeData_secondaryUser" product="tv">Erase this user\'s data on this TV without warning.</string>
+    <!-- Description of policy access to wipe the user's data -->
+    <string name="policydesc_wipeData_secondaryUser" product="default">Erase this user\'s data on this phone without warning.</string>
+    <!-- Title of policy access to set global proxy -->
+    <string name="policylab_setGlobalProxy">Set the device global proxy</string>
+    <!-- Description of policy access to set global proxy -->
     <string name="policydesc_setGlobalProxy">Set the device global proxy
-        to be used while policy is enabled. Only the first device admin
-        sets the effective global proxy.</string>
+    to be used while policy is enabled. Only the device owner can set the global proxy.</string>
     <!-- Title of policy access to enforce password expiration [CHAR LIMIT=30]-->
-    <string name="policylab_expirePassword">Set lock-screen password expiration</string>
+    <string name="policylab_expirePassword">Set screen lock password expiration</string>
     <!-- Description of policy access to enforce password expiration [CHAR LIMIT=110]-->
-    <string name="policydesc_expirePassword">Control how frequently the lock-screen password must be changed.</string>
+    <string name="policydesc_expirePassword">Change how frequently the screen lock password, PIN, or pattern must be changed.</string>
     <!-- Title of policy access to require encrypted storage [CHAR LIMIT=30]-->
     <string name="policylab_encryptedStorage">Set storage encryption</string>
     <!-- Description of policy access to require encrypted storage [CHAR LIMIT=110]-->
@@ -2445,9 +2462,9 @@
     <!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
     <string name="policydesc_disableCamera">Prevent use of all device cameras.</string>
     <!-- Title of policy access to disable all device cameras [CHAR LIMIT=30]-->
-    <string name="policylab_disableKeyguardFeatures">Disable features in keyguard</string>
+    <string name="policylab_disableKeyguardFeatures">Disable features of screen lock</string>
     <!-- Description of policy access to disable all device cameras [CHAR LIMIT=110]-->
-    <string name="policydesc_disableKeyguardFeatures">Prevent use of some features in keyguard.</string>
+    <string name="policydesc_disableKeyguardFeatures">Prevent use of some features of screen lock.</string>
 
     <!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
     <!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
@@ -5073,7 +5090,7 @@
     <string name="zen_mode_until">Until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g></string>
 
     <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
-    <string name="zen_mode_forever">Indefinitely</string>
+    <string name="zen_mode_forever">Until you turn this off</string>
 
     <!-- Content description for the Toolbar icon used to collapse an expanded action mode. [CHAR LIMIT=NONE] -->
     <string name="toolbar_collapse_description">Collapse</string>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index d75e496..9a64dec9 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -513,9 +513,7 @@
         <item name="background">@null</item>
     </style>
 
-    <style name="Widget.Material.ButtonBar.AlertDialog">
-        <item name="background">@null</item>
-    </style>
+    <style name="Widget.Material.ButtonBar.AlertDialog" />
 
     <style name="Widget.Material.SearchView">
         <item name="layout">@layout/search_view</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 615f445..39c0e8f 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -254,6 +254,7 @@
   <java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
   <java-symbol type="bool" name="config_enable_emergency_call_while_sim_locked" />
   <java-symbol type="bool" name="config_enable_puk_unlock_screen" />
+  <java-symbol type="bool" name="config_enableBurnInProtection" />
   <java-symbol type="bool" name="config_hotswapCapable" />
   <java-symbol type="bool" name="config_mms_content_disposition_support" />
   <java-symbol type="bool" name="config_networkSamplingWakesDevice" />
@@ -344,6 +345,11 @@
   <java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
   <java-symbol type="integer" name="config_bluetooth_max_advertisers" />
   <java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
+  <java-symbol type="integer" name="config_burnInProtectionMinHorizontalOffset" />
+  <java-symbol type="integer" name="config_burnInProtectionMaxHorizontalOffset" />
+  <java-symbol type="integer" name="config_burnInProtectionMinVerticalOffset" />
+  <java-symbol type="integer" name="config_burnInProtectionMaxVerticalOffset" />
+  <java-symbol type="integer" name="config_burnInProtectionMaxRadius" />
   <java-symbol type="integer" name="config_cursorWindowSize" />
   <java-symbol type="integer" name="config_drawLockTimeoutMillis" />
   <java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
@@ -754,7 +760,9 @@
   <java-symbol type="string" name="policydesc_resetPassword" />
   <java-symbol type="string" name="policydesc_setGlobalProxy" />
   <java-symbol type="string" name="policydesc_watchLogin" />
+  <java-symbol type="string" name="policydesc_watchLogin_secondaryUser" />
   <java-symbol type="string" name="policydesc_wipeData" />
+  <java-symbol type="string" name="policydesc_wipeData_secondaryUser" />
   <java-symbol type="string" name="policydesc_disableKeyguardFeatures" />
   <java-symbol type="string" name="policylab_disableCamera" />
   <java-symbol type="string" name="policylab_encryptedStorage" />
@@ -765,6 +773,7 @@
   <java-symbol type="string" name="policylab_setGlobalProxy" />
   <java-symbol type="string" name="policylab_watchLogin" />
   <java-symbol type="string" name="policylab_wipeData" />
+  <java-symbol type="string" name="policylab_wipeData_secondaryUser" />
   <java-symbol type="string" name="policylab_disableKeyguardFeatures" />
   <java-symbol type="string" name="postalTypeCustom" />
   <java-symbol type="string" name="postalTypeHome" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 0107356..d496e18 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -174,14 +174,14 @@
         <item name="windowSharedElementExitTransition">@transition/move</item>
 
         <!-- Dialog attributes -->
-        <item name="dialogTheme">@style/Theme.Material.Dialog</item>
+        <item name="dialogTheme">@style/ThemeOverlay.Material.Dialog</item>
         <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_material</item>
         <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
         <item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
         <item name="dialogPreferredPadding">@dimen/dialog_padding_material</item>
 
         <!-- AlertDialog attributes -->
-        <item name="alertDialogTheme">@style/Theme.Material.Dialog.Alert</item>
+        <item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog</item>
         <item name="alertDialogStyle">@style/AlertDialog.Material</item>
         <item name="alertDialogCenterButtons">false</item>
         <item name="alertDialogIcon">@drawable/ic_dialog_alert_material</item>
@@ -529,14 +529,14 @@
         <item name="windowActivityTransitions">true</item>
 
         <!-- Dialog attributes -->
-        <item name="dialogTheme">@style/Theme.Material.Light.Dialog</item>
+        <item name="dialogTheme">@style/ThemeOverlay.Material.Dialog</item>
         <item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_material</item>
         <item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
         <item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
         <item name="dialogPreferredPadding">@dimen/dialog_padding_material</item>
 
         <!-- AlertDialog attributes -->
-        <item name="alertDialogTheme">@style/Theme.Material.Light.Dialog.Alert</item>
+        <item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog</item>
         <item name="alertDialogStyle">@style/AlertDialog.Material.Light</item>
         <item name="alertDialogCenterButtons">false</item>
         <item name="alertDialogIcon">@drawable/ic_dialog_alert_material</item>
@@ -695,7 +695,7 @@
 
         <item name="dividerVertical">?attr/listDivider</item>
         <item name="dividerHorizontal">?attr/listDivider</item>
-        <item name="buttonBarStyle">@style/Widget.Material.Light.ButtonBar</item>
+        <item name="buttonBarStyle">@style/Widget.Material.Light.ButtonBar.AlertDialog</item>
         <item name="buttonBarButtonStyle">@style/Widget.Material.Light.Button.ButtonBar.AlertDialog</item>
         <item name="segmentedButtonStyle">@style/Widget.Material.Light.SegmentedButton</item>
 
@@ -839,7 +839,7 @@
          secondary text color, with the primary text color. -->
     <style name="ThemeOverlay.Material.ActionBar">
         <item name="colorControlNormal">?attr/textColorPrimary</item>
-        <item name="searchViewStyle">@style/Widget.Material.Light.SearchView.ActionBar</item>
+        <item name="searchViewStyle">@style/Widget.Material.SearchView.ActionBar</item>
     </style>
 
     <!-- Theme overlay that replaces colors with their dark versions and replaces the normal
@@ -850,6 +850,34 @@
         <item name="searchViewStyle">@style/Widget.Material.SearchView.ActionBar</item>
     </style>
 
+    <!-- Theme overlay that overrides window properties to display as a dialog. -->
+    <style name="ThemeOverlay.Material.Dialog">
+        <item name="colorBackground">@color/background_floating_material_light</item>
+        <item name="colorBackgroundCacheHint">@null</item>
+
+        <item name="windowFrame">@null</item>
+        <item name="windowTitleStyle">@style/DialogWindowTitle.Material</item>
+        <item name="windowTitleBackgroundStyle">@style/DialogWindowTitleBackground.Material</item>
+        <item name="windowBackground">@drawable/dialog_background_material</item>
+        <item name="windowElevation">@dimen/floating_window_z</item>
+        <item name="windowIsFloating">true</item>
+        <item name="windowContentOverlay">@null</item>
+        <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
+        <item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
+        <item name="windowActionBar">false</item>
+        <item name="windowActionModeOverlay">true</item>
+        <item name="windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
+
+        <item name="listPreferredItemPaddingLeft">?attr/dialogPreferredPadding</item>
+        <item name="listPreferredItemPaddingRight">?attr/dialogPreferredPadding</item>
+        <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
+        <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
+
+        <item name="listDivider">@null</item>
+
+        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+    </style>
+
     <!-- Variant of the material (dark) theme with no action bar. -->
     <style name="Theme.Material.NoActionBar">
         <item name="windowActionBar">false</item>
@@ -1033,12 +1061,6 @@
 
         <item name="colorBackgroundCacheHint">@null</item>
 
-        <item name="buttonBarStyle">@style/Widget.Material.ButtonBar.AlertDialog</item>
-        <item name="borderlessButtonStyle">@style/Widget.Material.Button.Borderless</item>
-
-        <item name="textAppearance">@style/TextAppearance.Material</item>
-        <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
-
         <item name="listPreferredItemPaddingLeft">24dip</item>
         <item name="listPreferredItemPaddingRight">24dip</item>
         <item name="listPreferredItemPaddingStart">24dip</item>
@@ -1150,12 +1172,6 @@
 
         <item name="colorBackgroundCacheHint">@null</item>
 
-        <item name="buttonBarStyle">@style/Widget.Material.Light.ButtonBar.AlertDialog</item>
-        <item name="borderlessButtonStyle">@style/Widget.Material.Light.Button.Borderless</item>
-
-        <item name="textAppearance">@style/TextAppearance.Material</item>
-        <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
-
         <item name="listPreferredItemPaddingLeft">24dip</item>
         <item name="listPreferredItemPaddingRight">24dip</item>
         <item name="listPreferredItemPaddingStart">24dip</item>
@@ -1254,8 +1270,6 @@
         <item name="colorPrimaryDark">@color/material_blue_grey_950</item>
         <item name="colorAccent">@color/material_deep_teal_500</item>
 
-        <item name="dialogTheme">@style/Theme.Material.Settings.Dialog</item>
-        <item name="alertDialogTheme">@style/Theme.Material.Settings.Dialog.Alert</item>
         <item name="presentationTheme">@style/Theme.Material.Settings.Dialog.Presentation</item>
         <item name="searchDialogTheme">@style/Theme.Material.Settings.SearchBar</item>
         <item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index 1ebc708..e730dff 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -24,9 +24,6 @@
         <item name="windowBackground">@color/black</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
-        <!-- We need the windows to be translucent for SwipeToDismiss layout
-             to work properly. -->
-        <item name="windowIsTranslucent">true</item>
         <item name="windowSwipeToDismiss">true</item>
         <!-- Required to force windowInsets dispatch through application UI. -->
         <item name="windowOverscan">true</item>
@@ -42,9 +39,6 @@
         <item name="windowBackground">@color/white</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
-        <!-- We need the windows to be translucent for SwipeToDismiss layout
-             to work properly. -->
-        <item name="windowIsTranslucent">true</item>
         <item name="windowSwipeToDismiss">true</item>
         <!-- Required to force windowInsets dispatch through application UI. -->
         <item name="windowOverscan">true</item>
diff --git a/docs/html/guide/topics/admin/device-admin.jd b/docs/html/guide/topics/admin/device-admin.jd
index bed4b4d..45bd76a 100644
--- a/docs/html/guide/topics/admin/device-admin.jd
+++ b/docs/html/guide/topics/admin/device-admin.jd
@@ -48,6 +48,11 @@
 provided by the Device Administration API to provide stronger security for
 employee devices that are powered by Android.</p>
 
+<p class="note"><strong>Note</strong> For information on building a Work Policy
+Controller for Android for Work deployments, see <a
+href="{@docRoot}training/enterprise/work-policy-ctrl.html">Building a Work
+Policy Controller</a>.</p>
+
 
 <h2 id="overview">Device Administration API Overview</h2>
 
@@ -712,4 +717,4 @@
 </pre>
 <p>
 See the Device Administration API sample for a complete example of how to enable storage encryption.
-</p>
\ No newline at end of file
+</p>
diff --git a/docs/html/images/enterprise/work-launcher.png b/docs/html/images/enterprise/work-launcher.png
new file mode 100644
index 0000000..3bbd835
--- /dev/null
+++ b/docs/html/images/enterprise/work-launcher.png
Binary files differ
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index 6fb906e..9caf938 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -1186,5 +1186,21 @@
       "training/multiscreen/index.html",
       "training/monitoring-device-state/index.html"
     ]
+  },
+  "training/work/apps": {
+    "title": "",
+    "resources": [
+      "training/enterprise/app-compatibility.html",
+      "training/enterprise/app-restrictions.html",
+      "samples/AppRestrictionSchema/index.html",
+      "samples/AppRestrictionEnforcer/index.html"
+    ]
+  },
+  "training/work/admin": {
+    "title": "",
+    "resources": [
+      "training/enterprise/work-policy-ctrl.html",
+      "samples/BasicManagedProfile/index.html"
+    ]
   }
 }
\ No newline at end of file
diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd
index d899ef3..45d1890 100644
--- a/docs/html/sdk/installing/index.jd
+++ b/docs/html/sdk/installing/index.jd
@@ -124,7 +124,7 @@
     <li>If the SDK is not already installed, follow the setup wizard to install the SDK and any
     necessary SDK tools.
     <p class="note"><strong>Note:</strong> You may also need to install the ia32-libs,
-    lib32ncurses5-dev, and lib32stc++6 packages. These packages are required to support 32-bit apps
+    lib32ncurses5-dev, and lib32stdc++6 packages. These packages are required to support 32-bit apps
     on a 64-bit machine. </p>
     </li>
   </ol>
diff --git a/docs/html/tools/help/android.jd b/docs/html/tools/help/android.jd
index 19891e8..0d7d2aa 100644
--- a/docs/html/tools/help/android.jd
+++ b/docs/html/tools/help/android.jd
@@ -6,25 +6,26 @@
 <p>{@code android} is an important development tool that lets you:</p>
 
   <ul>
-    <li>Create, delete, and view Android Virtual Devices (AVDs). See <a href= 
-    "{@docRoot}tools/devices/managing-avds-cmdline.html">Managing AVDs from the Command
-Line</a>.</li>
+    <li>Create, delete, and view Android Virtual Devices (AVDs). See <a href=
+    "{@docRoot}tools/devices/managing-avds-cmdline.html">Managing AVDs from the Command Line</a>.</li>
 
-    <li>Create and update Android projects. See <a href= 
+    <li>Create and update Android projects. See <a href=
     "{@docRoot}tools/projects/projects-cmdline.html">Managing Projects from
     the Command Line</a>.</li>
 
-    <li>Update your Android SDK with new platforms, add-ons, and documentation. See <a href= 
-    "{@docRoot}sdk/exploring.html">Exploring the SDK</a>.</li>
-  </ul>If you are using Eclipse, the <code>android</code> tool's features are integrated
-  into ADT, so you should not need to use this tool directly.
-  
+    <li>Update your Android SDK with new platforms, add-ons, and documentation. See <a href=
+    "{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</li>
+  </ul>
+
+<p>If you are using Android Studio or Eclipse, the <code>android</code> tool's features are
+integrated into the IDE, so you should not need to use this tool directly. </p>
+
   <p class="note"><strong>Note:</strong> The documentation of options below is not exhaustive
 and may be out of date. For the most current list of options, execute <code>android
 --help</code>.</p>
-  
-  
-  
+
+
+
 
   <h2>Syntax</h2>
   <pre>android [global options] action [action options]</pre>
diff --git a/docs/html/tools/help/draw9patch.jd b/docs/html/tools/help/draw9patch.jd
index 859b1cf..7c26441 100644
--- a/docs/html/tools/help/draw9patch.jd
+++ b/docs/html/tools/help/draw9patch.jd
@@ -2,42 +2,50 @@
 page.tags=NinePatch
 @jd:body
 
-<p>The Draw 9-patch tool allows you to easily create a 
-   {@link android.graphics.NinePatch} graphic using a WYSIWYG editor.</p>
-<p>For an introduction to Nine-patch graphics and how they work, please read 
-the section about Nine-patch in the 
-<a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">2D Graphics</a>
+<p>The Draw 9-patch tool is a WYSIWYG editor that allows you to create bitmap images that
+automatically resize to accommodate the contents of the view and the size of the screen. Selected
+parts of the image are scaled horizontally or vertically based indicators drawn within the image. </p>
+<p>For an introduction to NinePatch graphics and how they work, please read
+the section about NinePatch Drawables in the
+<a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">Canvas and Drawables</a>
 document.</p>
 
 <img src="{@docRoot}images/draw9patch-norm.png" style="float:right" alt="" height="300" width="341"
 />
 
-<p>Here's a quick guide to create a Nine-patch graphic using the Draw 9-patch tool.
-You'll need the PNG image with which you'd like to create a NinePatch.</p>
+<p>Here's a quick guide to create a NinePatch graphic using the Draw 9-patch tool.
+You'll need the PNG image with which you'd like to create a NinePatch image.</p>
 
 <ol>
-  <li>From a terminal, launch the <code>draw9patch</code> application from your SDK 
-    <code>/tools</code> directory.
+  <li>From a terminal, run the <code>draw9patch</code> command from your SDK
+    <code>sdk/tools</code> directory to launch the Draw 9-patch tool. 
     </li>
-  <li>Drag your PNG image into the Draw 9-patch window 
+  <li>Drag your PNG image into the Draw 9-patch window
     (or <strong>File</strong> > <strong>Open 9-patch...</strong> to locate the file).
     Your workspace will now open.
     <p>The left pane is your drawing area, in which you can edit the lines for the
-     stretchable patches and content area. The right 
+     stretchable patches and content area. The right
      pane is the preview area, where you can preview your graphic when stretched.</p>
     </li>
-  <li>Click within the 1-pixel perimeter to draw the lines that define the stretchable 
-    patches and (optional) content area. Right-click (or hold Shift and click, on Mac) to erase 
+  <li>Click within the 1-pixel perimeter to draw the lines that define the stretchable
+    patches and (optional) content area. Right-click (or hold Shift and click, on Mac) to erase
     previously drawn lines.
     </li>
   <li>When done, select <strong>File</strong> > <strong>Save 9-patch...</strong>
     <p>Your image will be saved with the <code>.9.png</code> file name.</p>
     </li>
 </ol>
-    <p class="note"><strong>Note:</strong> A normal PNG file (<code>*.png</code>) will be 
-     loaded with an empty one-pixel border added around the image, in which you can draw 
+
+   <p>To make sure that your NinePatch graphics scale down properly, verify that any
+   stretchable regions are at least 2x2 pixels in size.
+   Otherwise, they may disappear when scaled down. Also, provide one pixel of extra safe space in
+   the graphics before and after stretchable regions to avoid interpolation during scaling that may
+   cause the color at the boundaries to change. </p>
+
+    <p class="note"><strong>Note:</strong> A normal PNG file (<code>*.png</code>) will be
+     loaded with an empty one-pixel border added around the image, in which you can draw
      the stretchable patches and content area.
-     A previously saved 9-patch file (<code>*.9.png</code>) will be loaded as-is, 
+     A previously saved NinePatch file (<code>*.9.png</code>) will be loaded as-is,
      with no drawing area added, because it already exists.</p>
 
 <img src="{@docRoot}images/draw9patch-bad.png" style="float:right;clear:both" alt="" height="300" width="341"
diff --git a/docs/html/training/enterprise/app-compatibility.jd b/docs/html/training/enterprise/app-compatibility.jd
index 1ae1ee3..216a799 100644
--- a/docs/html/training/enterprise/app-compatibility.jd
+++ b/docs/html/training/enterprise/app-compatibility.jd
@@ -1,4 +1,6 @@
 page.title=Ensuring Compatibility with Managed Profiles
+page.metaDescription=Learn how to make sure your apps operate smoothly in a corporate environment by following some best practices.
+
 @jd:body
 
 <div id="tb-wrapper">
diff --git a/docs/html/training/enterprise/app-restrictions.jd b/docs/html/training/enterprise/app-restrictions.jd
new file mode 100644
index 0000000..fc5dfcc
--- /dev/null
+++ b/docs/html/training/enterprise/app-restrictions.jd
@@ -0,0 +1,351 @@
+page.title=Implementing App Restrictions
+page.metaDescription=Learn how to implement app restrictions and configuration settings that can be changed by other apps on the same device.
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#define_restrictions">Define App Restrictions</a></li>
+ <li><a href="#check_restrictions">Check App Restrictions</a></li>
+ <li><a href="#listen">Listen for App Restriction Changes</a></li>
+</ol>
+
+<!-- related docs (NOT javadocs) -->
+<h2>Resources</h2>
+<ul>
+  <li><a href="{@docRoot}samples/AppRestrictionSchema/index.html">AppRestrictionSchema</a>
+    sample app</li>
+  <li><a href="{@docRoot}samples/AppRestrictionEnforcer/index.html">AppRestrictionEnforcer</a>
+    sample app</li>
+</ul>
+
+</div>
+</div>
+
+<p>If you are developing apps for the enterprise market, you may need to satisfy
+particular requirements set by a company's policies. Application restrictions
+allow the enterprise administrator to remotely specify settings for apps.
+This capability is particularly useful for enterprise-approved apps deployed to
+a managed profile.</p>
+
+<p>For example, an enterprise might require that approved apps allow the
+enterprise administrator to:</p>
+
+<ul>
+  <li>Whitelist or blacklist URLs for a web browser</li>
+  <li>Configure whether an app is allowed to sync content via cellular, or just
+    by Wi-Fi</li>
+  <li>Configure the app's email settings</li>
+</ul>
+
+<p>
+  This guide shows how to implement these configuration settings in your app.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> For historical reasons, these configuration settings are known as
+  <em>restrictions,</em> and are implemented with files and classes that use this
+  term (such as {@link android.content.RestrictionsManager}). However, these
+  restrictions can actually implement a wide range of configuration options,
+  not just restrictions on app functionality.
+</p>
+
+<h2 id="overview">
+  Remote Configuration Overview
+</h2>
+
+<p>
+  Apps define the restrictions and configuration options that can be remotely
+  set by an administrator. These restrictions are
+  arbitrary configuration settings that can be changed by a restrictions
+  provider. If your app is running on an enterprise device's managed
+  profile, the enterprise administrator can change your app's restrictions.
+</p>
+
+<p>
+  The restrictions provider is another app running on the same device.
+  This app is typically controlled by the enterprise administrator. The
+  enterprise administrator communicates restriction changes to the restrictions
+  provider app. That app, in turn, changes the restrictions on your app.
+</p>
+
+<p>
+  To provide externally configurable restrictions:
+</p>
+
+<ul>
+  <li>Declare the restrictions in your app manifest. Doing so allows the
+  enterprise administrator to read the app's restrictions through Google
+  Play APIs.
+  </li>
+
+  <li>Whenever the app resumes, use the {@link
+    android.content.RestrictionsManager} object to check the current
+    restrictions, and change your app's UI and behavior to conform with those
+    restrictions.
+  </li>
+
+  <li>Listen for the
+  {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
+  ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent. When you receive this
+  broadcast, check the {@link android.content.RestrictionsManager} to see what
+  the current restrictions are, and make any necessary changes to your app's
+  behavior.
+  </li>
+</ul>
+
+<h2 id="define_restrictions">
+  Define App Restrictions
+</h2>
+
+<p>
+  Your app can support any restrictions you want to define. You declare the
+  app's restrictions in a <em>restrictions file</em>, and declare the
+  restrictions file in the manifest. Creating a restrictions file allows other
+  apps to examine the restrictions your app provides. Enterprise Mobility
+  Management (EMM) partners can read your app's restrictions by using Google
+  Play APIs.
+</p>
+
+<p>
+  To define your app's remote configuration options, put the following element
+  in your manifest's
+  <a href="{@docRoot}guide/topics/manifest/application-element.html">
+  <code>&lt;application&gt;</code></a> element:
+</p>
+
+<pre>&lt;meta-data android:name="android.content.APP_RESTRICTIONS"
+    android:resource="@xml/app_restrictions" /&gt;
+</pre>
+
+<p>
+  Create a file named <code>app_restrictions.xml</code> in your app's
+  <code>res/xml</code> directory. The structure of that file is described in
+  the reference for {@link android.content.RestrictionsManager}. The file has a
+  single top-level <code>&lt;restrictions&gt;</code> element, which contains
+  one <code>&lt;restriction&gt;</code> child element for every configuration
+  option the app has.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> Do not create localized versions of the restrictions
+  file. Your app is only allowed to have a single restrictions file,
+  so restrictions will be consistent for your app in all locales.
+</p>
+
+<p>
+  In an enterprise environment, an EMM will typically use the restrictions
+  schema to generate a remote console for IT administrators, so the
+  administrators can remotely configure your application.
+</p>
+
+<p>
+  For example, suppose your app can be remotely configured to allow or forbid
+  it to download data over a cellular connection. Your app could have a
+  <code>&lt;restriction&gt;</code> element like this:
+</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;restrictions xmlns:android="http://schemas.android.com/apk/res/android" &gt;
+
+  &lt;restriction
+    android:key="downloadOnCellular"
+    android:title="App is allowed to download data via cellular"
+    android:restrictionType="bool"
+    android:description="If 'false', app can only download data via Wi-Fi"
+    android:defaultValue="true" /&gt;
+
+&lt;/restrictions&gt;
+</pre>
+
+<p>
+  The supported types for the <code>android:restrictionType</code> element are
+  documented in the reference for {@link android.content.RestrictionsManager}.
+</p>
+
+<p>
+  You use each restriction's <code>android:key</code> attribute to read its
+  value from a restrictions bundle. For this reason, each restriction must have
+  a unique key string, and the string <em>cannot</em> be localized. It must be
+  specified with a string literal.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> In a production app, <code>android:title</code> and
+  <code>android:description</code> should be drawn from a localized resource
+  file, as described in <a href=
+  "{@docRoot}guide/topics/resources/localization.html">Localizing with
+  Resources</a>.
+</p>
+
+<p>
+  The restrictions provider can query the app to find details on the app's
+  available restrictions, including their description text. Restrictions
+  providers and enterprise administrators can change your app's restrictions at
+  any time, even when the app is not running.
+</p>
+
+<h2 id="check_restrictions">
+  Check App Restrictions
+</h2>
+
+<p>
+  Your app is not automatically notified when other apps change its restriction
+  settings. Instead, you need to check what the restrictions are when your app
+  starts or resumes, and listen for a system intent to find out if the
+  restrictions change while your app is running.
+</p>
+
+<p>
+  To find out the current restriction settings, your app uses a {@link
+  android.content.RestrictionsManager} object. Your app should check for the
+  current restrictions at the following times:
+</p>
+
+<ul>
+  <li>When the app starts or resumes, in its
+  {@link android.app.Activity#onResume onResume()} method
+  </li>
+
+  <li>When the app is notified of a restriction change, as described in
+    <a href="#listen">Listen for Device Configuration
+    Changes</a>
+  </li>
+</ul>
+
+<p>
+  To get a {@link android.content.RestrictionsManager} object, get the current
+  activity with {@link android.app.Fragment#getActivity getActivity()}, then
+  call that activity's {@link android.app.Activity#getSystemService
+  Activity.getSystemService()} method:
+</p>
+
+<pre>RestrictionsManager myRestrictionsMgr =
+    (RestrictionsManager) getActivity()
+        .getSystemService(Context.RESTRICTIONS_SERVICE);</pre>
+
+<p>
+  Once you have a {@link android.content.RestrictionsManager}, you can get the current restrictions
+  settings by calling its
+  {@link android.content.RestrictionsManager#getApplicationRestrictions
+  getApplicationRestrictions()} method:
+</p>
+
+<pre>Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();</pre>
+
+<p class="note">
+  <strong>Note:</strong> For convenience, you can also fetch the current
+  restrictions with a {@link android.os.UserManager}, by calling {@link
+  android.os.UserManager#getApplicationRestrictions
+  UserManager.getApplicationRestrictions()}. This method behaves exactly the
+  same as {@link android.content.RestrictionsManager#getApplicationRestrictions
+  RestrictionsManager.getApplicationRestrictions()}.
+</p>
+
+<p>
+  The {@link android.content.RestrictionsManager#getApplicationRestrictions
+  getApplicationRestrictions()} method requires reading from data storage, so
+  it should be done sparingly. Do not call this method every time you need to
+  know the current restrictions. Instead, you should call it once when your app
+  starts or resumes, and cache the fetched restrictions bundle. Then listen for
+  the {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
+  ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent to find out if restrictions
+  change while your app is active, as described in <a href="#listen">Listen for
+  Device Configuration Changes</a>.
+</p>
+
+<h3 id="read_restrictions">
+  Reading and applying restrictions
+</h3>
+
+<p>
+  The {@link android.content.RestrictionsManager#getApplicationRestrictions
+  getApplicationRestrictions()} method returns a {@link android.os.Bundle}
+  containing a key-value pair for each restriction that has been set. The
+  values are all of type <code>Boolean</code>, <code>int</code>,
+  <code>String</code>, and <code>String[]</code>. Once you have the
+  restrictions {@link android.os.Bundle}, you can check the current
+  restrictions settings with the standard {@link android.os.Bundle} methods for
+  those data types, such as {@link android.os.Bundle#getBoolean getBoolean()}
+  or
+  {@link android.os.Bundle#getString getString()}.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> The restrictions {@link android.os.Bundle} contains
+  one item for every restriction that has been explicitly set by a restrictions
+  provider. However, you <em>cannot</em> assume that a restriction will be
+  present in the bundle just because you defined a default value in the
+  restrictions XML file.
+</p>
+
+<p>
+  It is up to your app to take appropriate action based on the current
+  restrictions settings. For example, if your app has a restriction specifying
+  whether it can download data over a cellular connection, and you find that
+  the restriction is set to <code>false</code>, you would have to disable data
+  download except when the device has a Wi-Fi connection, as shown in the
+  following example code:
+</p>
+
+<pre>
+boolean appCanUseCellular;
+
+if appRestrictions.containsKey("downloadOnCellular") {
+    appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular");
+} else {
+    // here, cellularDefault is a boolean set with the restriction's
+    // default value
+    appCanUseCellular = cellularDefault;
+}
+
+if (!appCanUseCellular) {
+    // ...turn off app's cellular-download functionality
+    // ...show appropriate notices to user
+}</pre>
+
+<h2 id="listen">
+  Listen for App Restriction Changes
+</h2>
+
+<p>
+  Whenever an app's restrictions are changed, the system fires the
+  {@link android.content.Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED
+  ACTION_APPLICATION_RESTRICTIONS_CHANGED} intent. Your app has to listen for
+  this intent so you can change the app's behavior when the restriction settings
+  change. The following code shows how to dynamically register a broadcast
+  receiver for this intent:
+</p>
+
+<pre>IntentFilter restrictionsFilter =
+    new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
+
+BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
+  &#64;Override public void onReceive(Context context, Intent intent) {
+
+    // Get the current restrictions bundle
+    Bundle <code>appRestrictions</code> =
+
+    myRestrictionsMgr.getApplicationRestrictions();
+
+    // Check current restrictions settings, change your app's UI and
+    // functionality as necessary.
+
+  }
+
+};
+
+registerReceiver(restrictionsReceiver, restrictionsFilter);
+</pre>
+<p class="note">
+  <strong>Note:</strong> Ordinarily, your app does not need to be notified
+  about restriction changes when it is paused. Instead, you should unregister
+  your broadcast receiver when the app is paused. When the app resumes, you
+  first check for the current restrictions (as discussed in <a href=
+  "#check_restrictions">Check Device Restrictions</a>), then register your
+  broadcast receiver to make sure you're notified about restriction changes
+  that happen while the app is active.
+</p>
diff --git a/docs/html/training/enterprise/index.jd b/docs/html/training/enterprise/index.jd
index 0ac68cc..10be14e 100644
--- a/docs/html/training/enterprise/index.jd
+++ b/docs/html/training/enterprise/index.jd
@@ -1,58 +1,67 @@
-page.title=Developing for Enterprise
-page.tags=policy,privacy
-
-trainingnavtop=true
-startpage=true
-next.title=Enhancing Security with Device Management Policies
-next.link=device-management-policy.html
+page.title=Building Apps for Work
+meta.tags="work, enterprise, corporate"
+page.tags="work", "enterprise", "corporate"
+page.metaDescription=Learn how to build Android apps for the enterprise and take advantage of Google's Android for Work program.
+page.tags="education"
+page.article=true
 
 @jd:body
 
-<div id="tb-wrapper">
-<div id="tb">
+<img src="{@docRoot}images/enterprise/work-launcher.png"
+  width="300"
+  style="float:right;margin:0 0 20px 20px"
+  alt="Android for Work apps in a managed profile">
 
-<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
-<h2>Dependencies and prerequisites</h2>
-<ul>
-  <li>Android 2.2 (API Level 8) or higher</li>
-</ul>
+<p>
+  The Android framework provides features to support the security, data separation, and
+  administration needs of a enterprise environment. As an app developer, you can make your app more
+  appealing to corporate customers by gracefully handling enterprise security and feature
+  restrictions. You can also modify your app so that technology administrators can remotely
+  configure it for use with enterprise resources.
+</p>
 
-<!-- related docs (NOT javadocs) -->
-<h2>You should also read</h2>
-<ul>
-  <li><a href="{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a></li>
-</ul>
+<p>
+  To help businesses incorporate Android devices and apps into the workplace, Google provides the
+  <a href="http://www.google.com/work/android">Android for Work</a> program, which offers a suite
+  of APIs and services for device distribution and administration. Through this program companies
+  can connect with Enterprise Mobility Management (EMM) providers to help integrate Android with
+  their businesses.
+</p>
 
-<h2>Try it out</h2>
+<p>
+  For more information, follow the links below to learn how to update your Android app to support
+  the enterprise environment or build enterprise-specific solutions.
+</p>
 
-<div class="download-box">
- <a href="http://developer.android.com/shareables/training/DeviceManagement.zip"
-class="button">Download the sample</a>
- <p class="filename">DeviceManagement.zip</p>
-</div>
 
-</div>
+<h2 id="apps">App Development for Enterprises</h2>
+
+<p>
+  Learn how to make your app function smoothly in corporate environments that restrict device
+  features and data access. Go further to support enterprise use of your app by enabling
+  restrictions that corporate technology administrators can use to remotely configure your app:
+</p>
+
+<div class="dynamic-grid">
+  <div class="resource-widget resource-flow-layout landing col-12"
+    data-query="collection:training/work/apps"
+    data-cardSizes="9x3"
+    data-maxResults="6">
+  </div>
 </div>
 
 
-<p>In this class, you'll learn APIs and techniques you can use when developing applications
-for the enterprise.</p>
+<h2 id="admin">Device and App Administration</h2>
 
+<p>
+  Learn how to build policy controller apps that enable enterprise technology administrators
+  to manage devices, manage corporate apps, and provide access to company resources:
+</p>
 
-<h2>Lessons</h2>
-
-
-<dl>
-  <dt><b><a href="device-management-policy.html">Enhancing Security with Device Management
-Policies</a></b></dt>
-    <dd>In this lesson, you will learn how to create a security-aware application that manages
-access to its content by enforcing device management policies</dd>
-
-  <dt><b><a href="app-compatibility.html">Ensuring Compatibility with Managed Profiles</a></b></dt>
-
-    <dd>In this lesson, you will learn the best practices to follow to ensure
-      that your app functions properly on devices that use <a
-      href="{@docRoot}about/versions/android-5.0.html#Enterprise">managed
-      profiles</a></dd>
-
-</dl>
+<div class="dynamic-grid">
+  <div class="resource-widget resource-flow-layout landing col-12"
+    data-query="collection:training/work/admin"
+    data-cardSizes="9x3"
+    data-maxResults="4">
+  </div>
+</div>
diff --git a/docs/html/training/enterprise/work-policy-ctrl.jd b/docs/html/training/enterprise/work-policy-ctrl.jd
new file mode 100644
index 0000000..5854e65
--- /dev/null
+++ b/docs/html/training/enterprise/work-policy-ctrl.jd
@@ -0,0 +1,339 @@
+page.title=Building a Work Policy Controller
+page.metaDescription=Learn how to develop a Work Policy Controller to create and administer a managed profile on an employee's device.
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+
+<h2>This lesson teaches you to</h2>
+<ol>
+ <li><a href="#after_creating_profile">Create a Managed Profile</a></li>
+ <li><a href="#set_up_policies">Set Up Device Policies</a></li>
+ <li><a href="#apply_restrictions">Apply App Restrictions</a></li>
+</ol>
+
+<!-- related docs (NOT javadocs) -->
+
+<h2>
+  You should also read
+</h2>
+
+<ul>
+  <li>
+    <a href="{@docRoot}guide/topics/admin/device-admin.html">Device
+    Administration</a>
+  </li>
+</ul>
+
+<h2>Resources</h2>
+<ul>
+
+  <li>
+    <a href=
+    "{@docRoot}samples/BasicManagedProfile/index.html">BasicManagedProfile</a>
+  </li>
+
+  <li>
+    <a href=
+    "{@docRoot}samples/AppRestrictionEnforcer/index.html">AppRestrictionEnforcer</a>
+  </li>
+</ul>
+
+</div>
+</div>
+
+
+<p>
+  In an Android for Work deployment, an enterprise needs to maintain control
+  over certain aspects of the employees' devices. The enterprise needs to
+  ensure that work-related information is encrypted and is kept separate from
+  employees' personal data. The enterprise may also need to limit device
+  capabilities, such as whether the device is allowed to use its camera. And
+  the enterprise may require that approved apps provide app restrictions, so
+  the enterprise can turn app capability on or off as needed.
+</p>
+
+<p>
+  To handle these tasks, an enterprise develops and deploys a Work Policy
+  Controller app. This app is installed on each employee's device. The
+  controller app installed on each employee's device and creates a work user
+  profile, which accesses enterprise apps and data separately from the user's
+  personal account. The controller app also acts as the
+  bridge between the enterprise's management software and the device; the
+  enterprise tells the controller app when it needs to make configuration
+  changes, and the controller app makes the appropriate settings changes for the
+  device and for other apps.
+</p>
+
+<p>
+  This lesson describes how to develop a Work Policy Controller app for devices
+  in an Android for Work deployment. The lesson describes how to create a work
+  user profile, how to set device policies, and how to apply
+  restrictions to other apps running on the managed profile.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> This lesson does not cover the situation where the
+  only profile on the device is the managed profile, under the enterprise's
+  control.
+</p>
+
+<h2 id="overview">Device Administration Overview</h2>
+
+<p>
+  In an Android for Work deployment, the enterprise administrator can set
+  policies to control the behavior of employees' devices and apps. The
+  enterprise administrator sets these policies with software provided by their
+  Enterprise Mobility Management (EMM) provider. The EMM software communicates
+  with a Work Policy Controller on each device. The Work Policy Controller, in
+  turn, manages the settings and behavior of the work user profile on each
+  individual’s device.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> A Work Policy Controller is built on the existing
+  model used for device administration applications, as described in <a href=
+  "{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a>.
+  In particular, your app needs to create a subclass of {@link
+  android.app.admin.DeviceAdminReceiver}, as described in that document.
+</p>
+
+<h3 id="managed_profiles">Managed profiles</h3>
+
+<p>
+  Users often want to use their personal devices in an enterprise setting. This
+  situation can present enterprises with a dilemma. If the user can use their
+  own device, the enterprise has to worry that confidential information (like
+  employee emails and contacts) are on a device the enterprise does not
+  control.
+</p>
+
+<p>
+  To address this situation, Android 5.0 (API level 21) allows enterprises to
+  set up a special work user profile using the Managed Profile API. This
+  user profile is called a <em>managed profile</em>, or a <em>work profile</em>
+  in the Android for Work program. If a device has a
+  managed profile for work, the profile's settings are under the control of the
+  enterprise administrator. The administrator can choose which apps are allowed
+  for that profile, and can control just what device features are available to
+  the profile.
+</p>
+
+<h2 id="create_profile">Create a Managed Profile</h2>
+
+<p>To create a managed profile on a device that already has a personal profile,
+first check that the device can support a managed profile, by seeing if the
+device supports the {@link
+android.content.pm.PackageManager#FEATURE_MANAGED_USERS FEATURE_MANAGED_USERS}
+system feature:</p>
+
+<pre>PackageManager pm = getPackageManager();
+if (!pm.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS)) {
+
+    // This device does not support native managed profiles!
+
+}</pre>
+
+<p>If the device supports managed profiles, create one by sending an intent with
+an {@link android.app.admin.DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE
+ACTION_PROVISION_MANAGED_PROFILE} action. Include the device admin package
+name as an extra.</p>
+
+<pre>Activity provisioningActivity = getActivity();
+
+// You'll need the package name for the WPC app.
+String myWPCPackageName = "com.example.myWPCApp";
+
+// Set up the provisioning intent
+Intent provisioningIntent =
+        new Intent("android.app.action.PROVISION_MANAGED_PROFILE");
+intent.putExtra(myWPCPackageName,
+        provisioningActivity.getApplicationContext().getPackageName());
+
+if (provisioningIntent.resolveActivity(provisioningActivity.getPackageManager())
+         == null) {
+
+    // No handler for intent! Can't provision this device.
+    // Show an error message and cancel.
+} else {
+
+    // REQUEST_PROVISION_MANAGED_PROFILE is defined
+    // to be a suitable request code
+    startActivityForResult(provisioningIntent,
+            REQUEST_PROVISION_MANAGED_PROFILE);
+    provisioningActivity.finish();
+}</pre>
+
+<p>The system responds to this intent by doing the following:</p>
+
+<ul>
+  <li>Verifies that the device is encrypted. If it is not, the system prompts
+  the user to encrypt the device before proceeding.
+  </li>
+
+  <li>Creates a managed profile.
+  </li>
+
+  <li>Removes non-required applications from the managed profile.
+  </li>
+
+  <li>Copies the Work Policy Controller application into the managed profile and
+    sets it as the profile owner.
+  </li>
+</ul>
+
+<p>Override {@link android.app.Activity#onActivityResult onActivityResult()} to
+see whether the provisioning was successful, as shown in the following 
+example code:</p>
+
+<pre>&#64;Override
+public void onActivityResult(int requestCode, int resultCode, Intent data) {
+
+    // Check if this is the result of the provisioning activity
+    if (requestCode == REQUEST_PROVISION_MANAGED_PROFILE) {
+
+        // If provisioning was successful, the result code is 
+        // Activity.RESULT_OK
+        if (resultCode == Activity.RESULT_OK) {
+            // Hurray! Managed profile created and provisioned!
+        } else {
+            // Boo! Provisioning failed!
+        }
+        return;
+
+    } else {
+        // This is the result of some other activity, call the superclass
+        super.onActivityResult(requestCode, resultCode, data);
+    }
+}</pre>
+
+<h3 id="after_creating_profile">After Creating the Managed Profile</h3>
+
+<p>When the profile has been provisioned, the system calls the Work Policy
+Controller app's {@link
+android.app.admin.DeviceAdminReceiver#onProfileProvisioningComplete
+DeviceAdminReceiver.onProfileProvisioningComplete()} method. Override this
+callback method to finish enabling the managed profile.</p>
+
+<p>Typically, your {@link
+android.app.admin.DeviceAdminReceiver#onProfileProvisioningComplete
+DeviceAdminReceiver.onProfileProvisioningComplete()} callback implementation
+would perform these tasks:</p>
+
+<ul>
+  <li>Verify that the device is complying with the EMM's device policies, as
+  described in <a href="#set_up_policies">Set Up Device Policies</a>
+  </li>
+
+  <li>Enable any system applications that the administrator chooses to make
+  available within the managed profile, using {@link
+  android.app.admin.DevicePolicyManager#enableSystemApp
+  DevicePolicyManager.enableSystemApp()}   </li>
+
+  <li>If the device uses Google Play for Work, add the Google account
+  to the managed profile with {@link android.accounts.AccountManager#addAccount
+  AccountManager.addAccount()}, so administrators can install
+  applications to the device
+  </li>
+</ul>
+
+<p>Once you have completed these tasks, call the device policy manager's
+{@link android.app.admin.DevicePolicyManager#setProfileEnabled
+setProfileEnabled()} method to activate the managed profile:</p>
+
+
+<pre>// Get the device policy manager
+DevicePolicyManager myDevicePolicyMgr =
+        (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
+
+ComponentName componentName = myDeviceAdminReceiver.getComponentName(this);
+
+// Set the name for the newly created managed profile.
+myDevicePolicyMgr.setProfileName(componentName, "My New Managed Profile");
+
+// ...and enable the profile
+manager.setProfileEnabled(componentName);</pre>
+
+<h2 id="set_up_policies">Set Up Device Policies</h2>
+
+<p>
+  The Work Policy Controller app is responsible for applying the enterprise's
+  device policies. For example, a particular enterprise might require that all
+  devices become locked after a certain number of failed attempts to enter the
+  device password. The controller app queries the EMM to find out what
+  the current policies are, then uses the <a href=
+  "{@docRoot}guide/topics/admin/device-admin.html">Device Administration</a>
+  API to apply those policies.
+</p>
+
+<p>For information on how to apply device policies, see the 
+<a href="{@docRoot}guide/topics/admin/device-admin.html#policies">Device
+Administration</a> guide.</p>
+
+
+<h2 id="apply_restrictions">Apply App Restrictions</h2>
+
+<p>Enterprise environments may require that approved apps implement apps
+implement security or feature restrictions. App developers must implement these
+restrictions and declare them for use by enterprise administrators, as described
+in <a href="{@docRoot}training/enterprise/app-restrictions.html">Implementing
+App Restrictions</a>. The Work Policy Controller receives restriction changes
+from the enterprise administrator, and forwards those restriction changes to the
+apps.</p>
+
+<p>For example, a particular news app might have a restriction setting that
+controls whether the app is allowed to download videos over a cellular
+network. When the EMM wants to disable cellular downloads, it sends a
+notification to the controller app. The controller app, in turn,
+notifies the news app that the restriction setting has changed.</p>
+
+<p class="note"><strong>Note:</strong> This document covers how the Work Policy
+Controller app changes the restriction settings for the other apps on the
+managed profile. Details on how the Work Policy Controller app communicates with
+the EMM are out of scope for this document.</p>
+
+<p>To change an app's restrictions, call the {@link
+android.app.admin.DevicePolicyManager#setApplicationRestrictions
+DevicePolicyManager.setApplicationRestrictions()} method. This method is passed
+three parameters: the controller app's {@link
+android.app.admin.DeviceAdminReceiver}, the package name of the app whose
+restrictions are being changed, and a {@link android.os.Bundle Bundle} that
+contains the restrictions you want to set.</p>
+
+<p>For example, suppose there's an app on the managed profile with the package
+name <code>"com.example.newsfetcher"</code>. This app has a single boolean
+restriction that can be configured, with the key
+<code>"downloadByCellular"</code>. If this restriction is set to
+<code>false</code>, the newsfetcher app is not allowed to download data through
+a cellular network; it must use a Wi-Fi network instead.</p>
+
+<p>
+  If your Work Policy Controller app needs to turn off cellular downloads, it
+  would first fetch the device policy service object, as described above. It
+  then assembles a restrictions bundle and passes this bundle to {@link
+  android.app.admin.DevicePolicyManager#setApplicationRestrictions
+  setApplicationRestrictions()}:
+</p>
+
+<pre>// Fetch the DevicePolicyManager
+DevicePolicyManager myDevicePolicyMgr =
+        (DevicePolicyManager) thisActivity
+                .getSystemService(Context.DEVICE_POLICY_SERVICE);
+
+// Set up the restrictions bundle
+bundle restrictionsBundle = new Bundle();
+restrictionsBundle.putBoolean("downloadByCellular", false);
+
+// Pass the restrictions to the policy manager. Assume the WPC app
+// already has a DeviceAdminReceiver defined (myDeviceAdminReceiver).
+myDevicePolicyMgr.setApplicationRestrictions(
+        myDeviceAdminReceiver, "com.example.newsfetcher", restrictionsBundle);</pre>
+
+
+<p class="note"><strong>Note:</strong> The device policy service conveys the restrictions
+change to the app you name. However, it is up to that app to actually implement
+the restriction. For example, in this case, the app would be responsible for
+disabling its ability to use cellular networks for video downloads. Setting the
+restriction does not cause the system to enforce this restriction on the app.
+For more information, see <a href="{@docRoot}training/enterprise/app-
+restrictions.html">Implementing App Restrictions</a>.</p>
diff --git a/docs/html/training/material/animations.jd b/docs/html/training/material/animations.jd
index efc0ee3..86e91a7 100644
--- a/docs/html/training/material/animations.jd
+++ b/docs/html/training/material/animations.jd
@@ -46,9 +46,10 @@
 background as:</p>
 
 <ul>
-<li><code>?android:attr/selectableItemBackground</code> for a bounded ripple</li>
+<li><code>?android:attr/selectableItemBackground</code> for a bounded ripple.</li>
 <li><code>?android:attr/selectableItemBackgroundBorderless</code> for a ripple that extends beyond
-the view</li>
+the view. It will be drawn upon, and bounded by, the nearest parent of the view with a non-null
+background.</li>
 </ul>
 
 <p class="note"><strong>Note:</strong> <code>selectableItemBackgroundBorderless</code> is a new
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index c59d8ff..89e72f1 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -1040,6 +1040,32 @@
   <!-- End: Building for Auto -->
 
 
+  <!-- Start: Building for Work -->
+  <li class="nav-section">
+    <div class="nav-section-header">
+      <a href="<?cs var:toroot ?>training/enterprise/index.html">
+      <span class="small">Building Apps for</span><br/>
+              Work
+      </a>
+    </div>
+    <ul>
+      <li><a href="<?cs var:toroot ?>training/enterprise/app-compatibility.html">
+        Ensuring Compatibility with Managed Profiles
+      </a>
+      </li>
+      <li><a href="<?cs var:toroot ?>training/enterprise/app-restrictions.html">
+        Implementing App Restrictions
+      </a>
+      </li>
+      <li><a href="<?cs var:toroot ?>training/enterprise/work-policy-ctrl.html">
+        Building a Work Policy Controller
+      </a>
+      </li>
+    </ul>
+  </li>
+  <!-- End: Building for Work -->
+
+
   <li class="nav-section">
     <div class="nav-section-header">
       <a href="<?cs var:toroot ?>training/best-ux.html">
@@ -1752,10 +1778,6 @@
             Enhancing Security with Device Management Policies
           </a>
           </li>
-          <li><a href="<?cs var:toroot ?>training/enterprise/app-compatibility.html">
-            Ensuring Compatibility with Managed Profiles
-          </a>
-          </li>
         </ul>
       </li>
     </ul>
@@ -1887,4 +1909,4 @@
     buildToggleLists();
     changeNavLang(getLangPref());
 //-->
-</script>
\ No newline at end of file
+</script>
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index db94d89..24e0d6a 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -37,38 +37,47 @@
 /**
  * @hide
  */
-public class AnimatedRotateDrawable extends DrawableWrapper implements Runnable, Animatable {
+public class AnimatedRotateDrawable extends DrawableWrapper implements Animatable {
     private AnimatedRotateState mState;
 
     private float mCurrentDegrees;
     private float mIncrement;
+
+    /** Whether this drawable is currently animating. */
     private boolean mRunning;
 
+    /**
+     * Creates a new animated rotating drawable with no wrapped drawable.
+     */
     public AnimatedRotateDrawable() {
         this(new AnimatedRotateState(null), null);
     }
 
     @Override
     public void draw(Canvas canvas) {
-        int saveCount = canvas.save();
+        final Drawable drawable = getDrawable();
+        final Rect bounds = drawable.getBounds();
+        final int w = bounds.right - bounds.left;
+        final int h = bounds.bottom - bounds.top;
 
         final AnimatedRotateState st = mState;
-        final Drawable drawable = st.mDrawable;
-        final Rect bounds = drawable.getBounds();
+        final float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
+        final float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
 
-        int w = bounds.right - bounds.left;
-        int h = bounds.bottom - bounds.top;
-
-        float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
-        float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
-
+        final int saveCount = canvas.save();
         canvas.rotate(mCurrentDegrees, px + bounds.left, py + bounds.top);
-
         drawable.draw(canvas);
-
         canvas.restoreToCount(saveCount);
     }
 
+    /**
+     * Starts the rotation animation.
+     * <p>
+     * The animation will run until {@link #stop()} is called. Calling this
+     * method while the animation is already running has no effect.
+     *
+     * @see #stop()
+     */
     @Override
     public void start() {
         if (!mRunning) {
@@ -77,10 +86,15 @@
         }
     }
 
+    /**
+     * Stops the rotation animation.
+     *
+     * @see #start()
+     */
     @Override
     public void stop() {
         mRunning = false;
-        unscheduleSelf(this);
+        unscheduleSelf(mNextFrame);
     }
 
     @Override
@@ -89,20 +103,8 @@
     }
 
     private void nextFrame() {
-        unscheduleSelf(this);
-        scheduleSelf(this, SystemClock.uptimeMillis() + mState.mFrameDuration);
-    }
-
-    @Override
-    public void run() {
-        // TODO: This should be computed in draw(Canvas), based on the amount
-        // of time since the last frame drawn
-        mCurrentDegrees += mIncrement;
-        if (mCurrentDegrees > (360.0f - mIncrement)) {
-            mCurrentDegrees = 0.0f;
-        }
-        invalidateSelf();
-        nextFrame();
+        unscheduleSelf(mNextFrame);
+        scheduleSelf(mNextFrame, SystemClock.uptimeMillis() + mState.mFrameDuration);
     }
 
     @Override
@@ -114,7 +116,7 @@
                 nextFrame();
             }
         } else {
-            unscheduleSelf(this);
+            unscheduleSelf(mNextFrame);
         }
         return changed;
     }
@@ -208,11 +210,6 @@
     }
 
     static final class AnimatedRotateState extends DrawableWrapper.DrawableWrapperState {
-        Drawable mDrawable;
-        int[] mThemeAttrs;
-
-        int mChangingConfigurations;
-
         boolean mPivotXRel = false;
         float mPivotX = 0;
         boolean mPivotYRel = false;
@@ -220,9 +217,6 @@
         int mFrameDuration = 150;
         int mFramesCount = 12;
 
-        private boolean mCanConstantState;
-        private boolean mCheckedConstantState;
-
         public AnimatedRotateState(AnimatedRotateState orig) {
             super(orig);
 
@@ -240,26 +234,6 @@
         public Drawable newDrawable(Resources res) {
             return new AnimatedRotateDrawable(this, res);
         }
-
-        @Override
-        public boolean canApplyTheme() {
-            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
-                    || super.canApplyTheme();
-        }
-
-        @Override
-        public int getChangingConfigurations() {
-            return mChangingConfigurations;
-        }
-
-        public boolean canConstantState() {
-            if (!mCheckedConstantState) {
-                mCanConstantState = mDrawable.getConstantState() != null;
-                mCheckedConstantState = true;
-            }
-
-            return mCanConstantState;
-        }
     }
 
     private AnimatedRotateDrawable(AnimatedRotateState state, Resources res) {
@@ -276,7 +250,7 @@
 
         // Force the wrapped drawable to use filtering and AA, if applicable,
         // so that it looks smooth when rotated.
-        final Drawable drawable = state.mDrawable;
+        final Drawable drawable = getDrawable();
         if (drawable != null) {
             drawable.setFilterBitmap(true);
             if (drawable instanceof BitmapDrawable) {
@@ -284,4 +258,18 @@
             }
         }
     }
+
+    private final Runnable mNextFrame = new Runnable() {
+        @Override
+        public void run() {
+            // TODO: This should be computed in draw(Canvas), based on the amount
+            // of time since the last frame drawn
+            mCurrentDegrees += mIncrement;
+            if (mCurrentDegrees > (360.0f - mIncrement)) {
+                mCurrentDegrees = 0.0f;
+            }
+            invalidateSelf();
+            nextFrame();
+        }
+    };
 }
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 74ff1b0..5ccb165 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -31,20 +31,23 @@
 import android.util.AttributeSet;
 
 /**
- * An object used to create frame-by-frame animations, defined by a series of Drawable objects,
- * which can be used as a View object's background.
+ * An object used to create frame-by-frame animations, defined by a series of
+ * Drawable objects, which can be used as a View object's background.
  * <p>
- * The simplest way to create a frame-by-frame animation is to define the animation in an XML
- * file, placed in the res/drawable/ folder, and set it as the background to a View object. Then, call
- * {@link #start()} to run the animation.
+ * The simplest way to create a frame-by-frame animation is to define the
+ * animation in an XML file, placed in the res/drawable/ folder, and set it as
+ * the background to a View object. Then, call {@link #start()} to run the
+ * animation.
  * <p>
- * An AnimationDrawable defined in XML consists of a single <code>&lt;animation-list></code> element,
- * and a series of nested <code>&lt;item></code> tags. Each item defines a frame of the animation.
- * See the example below.
- * </p>
- * <p>spin_animation.xml file in res/drawable/ folder:</p>
- * <pre>&lt;!-- Animation frames are wheel0.png -- wheel5.png files inside the
- * res/drawable/ folder --&gt;
+ * An AnimationDrawable defined in XML consists of a single
+ * {@code &lt;animation-list&gt;} element and a series of nested
+ * {@code &lt;item&gt;} tags. Each item defines a frame of the animation. See
+ * the example below.
+ * <p>
+ * spin_animation.xml file in res/drawable/ folder:
+ * <pre>
+ * &lt;!-- Animation frames are wheel0.png through wheel5.png
+ *     files inside the res/drawable/ folder --&gt;
  * &lt;animation-list android:id=&quot;@+id/selected&quot; android:oneshot=&quot;false&quot;&gt;
  *    &lt;item android:drawable=&quot;@drawable/wheel0&quot; android:duration=&quot;50&quot; /&gt;
  *    &lt;item android:drawable=&quot;@drawable/wheel1&quot; android:duration=&quot;50&quot; /&gt;
@@ -53,8 +56,8 @@
  *    &lt;item android:drawable=&quot;@drawable/wheel4&quot; android:duration=&quot;50&quot; /&gt;
  *    &lt;item android:drawable=&quot;@drawable/wheel5&quot; android:duration=&quot;50&quot; /&gt;
  * &lt;/animation-list&gt;</pre>
- *
- * <p>Here is the code to load and play this animation.</p>
+ * <p>
+ * Here is the code to load and play this animation.
  * <pre>
  * // Load the ImageView that will host the animation and
  * // set its background to our AnimationDrawable XML resource.
@@ -128,13 +131,17 @@
     }
 
     /**
-     * <p>Starts the animation, looping if necessary. This method has no effect
-     * if the animation is running. Do not call this in the {@link android.app.Activity#onCreate}
-     * method of your activity, because the {@link android.graphics.drawable.AnimationDrawable} is
-     * not yet fully attached to the window. If you want to play
-     * the animation immediately, without requiring interaction, then you might want to call it
-     * from the {@link android.app.Activity#onWindowFocusChanged} method in your activity,
-     * which will get called when Android brings your window into focus.</p>
+     * Starts the animation, looping if necessary. This method has no effect
+     * if the animation is running.
+     * <p>
+     * <strong>Note:</strong> Do not call this in the
+     * {@link android.app.Activity#onCreate} method of your activity, because
+     * the {@link AnimationDrawable} is not yet fully attached to the window.
+     * If you want to play the animation immediately without requiring
+     * interaction, then you might want to call it from the
+     * {@link android.app.Activity#onWindowFocusChanged} method in your
+     * activity, which will get called when Android brings your window into
+     * focus.
      *
      * @see #isRunning()
      * @see #stop()
@@ -149,8 +156,8 @@
     }
 
     /**
-     * <p>Stops the animation. This method has no effect if the animation is
-     * not running.</p>
+     * Stops the animation. This method has no effect if the animation is not
+     * running.
      *
      * @see #isRunning()
      * @see #start()
@@ -165,7 +172,7 @@
     }
 
     /**
-     * <p>Indicates whether the animation is currently running or not.</p>
+     * Indicates whether the animation is currently running or not.
      *
      * @return true if the animation is running, false otherwise
      */
@@ -175,8 +182,8 @@
     }
 
     /**
-     * <p>This method exists for implementation purpose only and should not be
-     * called directly. Invoke {@link #start()} instead.</p>
+     * This method exists for implementation purpose only and should not be
+     * called directly. Invoke {@link #start()} instead.
      *
      * @see #start()
      */
@@ -208,7 +215,7 @@
 
     /**
      * @return The duration in milliseconds of the frame at the
-     * specified index
+     *         specified index
      */
     public int getDuration(int i) {
         return mAnimationState.mDurations[i];
@@ -231,12 +238,12 @@
     }
 
     /**
-     * Add a frame to the animation
+     * Adds a frame to the animation
      *
      * @param frame The frame to add
      * @param duration How long in milliseconds the frame should appear
      */
-    public void addFrame(Drawable frame, int duration) {
+    public void addFrame(@NonNull Drawable frame, int duration) {
         mAnimationState.addFrame(frame, duration);
         if (mCurFrame < 0) {
             setFrame(0, true, false);
@@ -244,13 +251,16 @@
     }
 
     private void nextFrame(boolean unschedule) {
-        int next = mCurFrame+1;
-        final int N = mAnimationState.getChildCount();
-        if (next >= N) {
-            next = 0;
+        int nextFrame = mCurFrame + 1;
+        final int numFrames = mAnimationState.getChildCount();
+        final boolean isLastFrame = mAnimationState.mOneShot && nextFrame >= (numFrames - 1);
+
+        // Loop if necessary. One-shot animations should never hit this case.
+        if (!mAnimationState.mOneShot && nextFrame >= numFrames) {
+            nextFrame = 0;
         }
 
-        setFrame(next, unschedule, !mAnimationState.mOneShot || next < (N - 1));
+        setFrame(nextFrame, unschedule, !isLastFrame);
     }
 
     private void setFrame(int frame, boolean unschedule, boolean animate) {
@@ -262,6 +272,7 @@
         selectDrawable(frame);
         if (unschedule || animate) {
             unscheduleSelf(this);
+            mRunning = false;
         }
         if (animate) {
             // Unscheduling may have clobbered these values; restore them
@@ -341,6 +352,7 @@
     }
 
     @Override
+    @NonNull
     public Drawable mutate() {
         if (!mMutated && super.mutate() == this) {
             mAnimationState.mutate();
@@ -366,8 +378,7 @@
         private int[] mDurations;
         private boolean mOneShot = false;
 
-        AnimationState(AnimationState orig, AnimationDrawable owner,
-                Resources res) {
+        AnimationState(AnimationState orig, AnimationDrawable owner, Resources res) {
             super(orig, owner, res);
 
             if (orig != null) {
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index b0cd386..97f7105 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -58,7 +58,7 @@
      * No-arg constructor used by drawable inflation.
      */
     InsetDrawable() {
-        this(new InsetState(), null);
+        this(new InsetState(null), null);
     }
 
     /**
@@ -82,7 +82,7 @@
      */
     public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,int insetRight,
             int insetBottom) {
-        this(new InsetState(), null);
+        this(new InsetState(null), null);
 
         mState.mInsetLeft = insetLeft;
         mState.mInsetTop = insetTop;
@@ -267,10 +267,6 @@
         int mInsetRight = 0;
         int mInsetBottom = 0;
 
-        InsetState() {
-            this(null);
-        }
-
         InsetState(InsetState orig) {
             super(orig);
 
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 595061c..ca161ee 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -58,10 +58,10 @@
     private RotateState mState;
 
     /**
-     * Create a new rotating drawable with an empty state.
+     * Creates a new rotating drawable with no wrapped drawable.
      */
     public RotateDrawable() {
-        this(null, null);
+        this(new RotateState(null), null);
     }
 
     @Override
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk
index 5dacbb5..ecb625b 100644
--- a/libs/hwui/Android.common.mk
+++ b/libs/hwui/Android.common.mk
@@ -104,6 +104,14 @@
     LOCAL_CFLAGS += -fno-omit-frame-pointer -marm -mapcs
 endif
 
+ifeq (true, $(HWUI_NULL_GPU))
+    LOCAL_SRC_FILES += \
+        tests/nullegl.cpp \
+        tests/nullgles.cpp
+
+    LOCAL_CFLAGS += -DHWUI_NULL_GPU
+endif
+
 # Defaults for ATRACE_TAG and LOG_TAG for libhwui
 LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\"
 
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index bd933b8..e5489a8 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -107,14 +107,6 @@
         startMark = startMarkNull;
         endMark = endMarkNull;
     }
-
-    if (mExtensions.hasDebugLabel() && (drawDeferDisabled || drawReorderDisabled)) {
-        setLabel = glLabelObjectEXT;
-        getLabel = glGetObjectLabelEXT;
-    } else {
-        setLabel = setLabelNull;
-        getLabel = getLabelNull;
-    }
 }
 
 void Caches::initConstraints() {
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 92a87e2..8aea8ff 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -207,9 +207,6 @@
     PFNGLPUSHGROUPMARKEREXTPROC startMark;
     PFNGLPOPGROUPMARKEREXTPROC endMark;
 
-    PFNGLLABELOBJECTEXTPROC setLabel;
-    PFNGLGETOBJECTLABELEXTPROC getLabel;
-
     // TEMPORARY properties
     void initTempProperties();
     void setTempProperty(const char* name, const char* value);
@@ -244,14 +241,6 @@
     static void startMarkNull(GLsizei length, const GLchar* marker) { }
     static void endMarkNull() { }
 
-    static void setLabelNull(GLenum type, uint object, GLsizei length,
-            const char* label) { }
-    static void getLabelNull(GLenum type, uint object, GLsizei bufferSize,
-            GLsizei* length, char* label) {
-        if (length) *length = 0;
-        if (label) *label = '\0';
-    }
-
     RenderState* mRenderState;
 
     // Used to render layers
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index c68822b..2a82216 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -55,7 +55,6 @@
     mHasFramebufferFetch = hasGlExtension("GL_NV_shader_framebuffer_fetch");
     mHasDiscardFramebuffer = hasGlExtension("GL_EXT_discard_framebuffer");
     mHasDebugMarker = hasGlExtension("GL_EXT_debug_marker");
-    mHasDebugLabel = hasGlExtension("GL_EXT_debug_label");
     mHasTiledRendering = hasGlExtension("GL_QCOM_tiled_rendering");
     mHas1BitStencil = hasGlExtension("GL_OES_stencil1");
     mHas4BitStencil = hasGlExtension("GL_OES_stencil4");
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 731001a..e7d317d 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -40,7 +40,6 @@
     inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
     inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
     inline bool hasDebugMarker() const { return mHasDebugMarker; }
-    inline bool hasDebugLabel() const { return mHasDebugLabel; }
     inline bool hasTiledRendering() const { return mHasTiledRendering; }
     inline bool has1BitStencil() const { return mHas1BitStencil; }
     inline bool has4BitStencil() const { return mHas4BitStencil; }
@@ -68,7 +67,6 @@
     bool mHasFramebufferFetch;
     bool mHasDiscardFramebuffer;
     bool mHasDebugMarker;
-    bool mHasDebugLabel;
     bool mHasTiledRendering;
     bool mHas1BitStencil;
     bool mHas4BitStencil;
diff --git a/libs/hwui/tests/Android.mk b/libs/hwui/tests/Android.mk
index a69f3fb..51898d2 100644
--- a/libs/hwui/tests/Android.mk
+++ b/libs/hwui/tests/Android.mk
@@ -25,6 +25,8 @@
 LOCAL_MODULE_STEM_32 := hwuitest
 LOCAL_MODULE_STEM_64 := hwuitest64
 
+HWUI_NULL_GPU := false
+
 include $(LOCAL_PATH)/Android.common.mk
 
 LOCAL_SRC_FILES += \
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp
index b61d72f..0d1e63e 100644
--- a/libs/hwui/tests/main.cpp
+++ b/libs/hwui/tests/main.cpp
@@ -93,16 +93,16 @@
         animation.createContent(width, height, renderer);
         endRecording(renderer, rootNode);
 
-        for (int i = 0; i < 150; i++) {
+        for (int i = 0; i < animation.getFrameCount(); i++) {
+#if !HWUI_NULL_GPU
             testContext.waitForVsync();
+#endif
 
             ATRACE_NAME("UI-Draw Frame");
             animation.doFrame(i);
             proxy->syncAndDrawFrame();
         }
 
-        sleep(5);
-
         rootNode->decStrong(nullptr);
     }
 };
diff --git a/libs/hwui/tests/nullegl.cpp b/libs/hwui/tests/nullegl.cpp
new file mode 100644
index 0000000..b6cc2f2
--- /dev/null
+++ b/libs/hwui/tests/nullegl.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+static EGLDisplay gDisplay = (EGLDisplay) 1;
+
+typedef struct {
+    EGLSurface surface;
+    EGLContext context;
+} ThreadState;
+
+static pthread_key_t ThreadStateKey;
+static pthread_once_t ThreadStateSetupOnce = PTHREAD_ONCE_INIT;
+
+static void destroyThreadState(void* state) {
+    free(state);
+}
+
+static void makeThreadState() {
+    pthread_key_create(&ThreadStateKey, destroyThreadState);
+}
+
+ThreadState* getThreadState() {
+    ThreadState* ptr;
+    pthread_once(&ThreadStateSetupOnce, makeThreadState);
+    if ((ptr = (ThreadState*) pthread_getspecific(ThreadStateKey)) == NULL) {
+        ptr = (ThreadState*) calloc(1, sizeof(ThreadState));
+        ptr->context = EGL_NO_CONTEXT;
+        ptr->surface = EGL_NO_SURFACE;
+        pthread_setspecific(ThreadStateKey, ptr);
+    }
+    return ptr;
+}
+
+EGLint eglGetError(void) {
+    return EGL_SUCCESS;
+}
+
+EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) {
+    return gDisplay;
+}
+
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) {
+    return EGL_TRUE;
+}
+
+EGLBoolean eglTerminate(EGLDisplay dpy) {
+    return EGL_TRUE;
+}
+
+const char * eglQueryString(EGLDisplay dpy, EGLint name) {
+    return "";
+}
+
+EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
+               EGLConfig *configs, EGLint config_size,
+               EGLint *num_config) {
+    memset(configs, 9, sizeof(EGLConfig) * config_size);
+    *num_config = config_size;
+    return EGL_TRUE;
+}
+
+EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
+                  EGLNativeWindowType win,
+                  const EGLint *attrib_list) {
+    return (EGLSurface) malloc(sizeof(void*));
+}
+
+EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
+                   const EGLint *attrib_list) {
+    return (EGLSurface) malloc(sizeof(void*));
+}
+
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
+    free(surface);
+    return EGL_TRUE;
+}
+
+EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
+               EGLint attribute, EGLint *value) {
+    *value = 1000;
+    return EGL_TRUE;
+}
+
+EGLBoolean eglReleaseThread(void) {
+    return EGL_TRUE;
+}
+
+EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
+                EGLint attribute, EGLint value) {
+    return EGL_TRUE;
+}
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) {
+    return EGL_TRUE;
+}
+
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
+                EGLContext share_context,
+                const EGLint *attrib_list) {
+    return (EGLContext) malloc(sizeof(void*));
+}
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
+    free(ctx);
+    return EGL_TRUE;
+}
+
+EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
+              EGLSurface read, EGLContext ctx) {
+    ThreadState* state = getThreadState();
+    state->surface = draw;
+    state->context = ctx;
+    return EGL_TRUE;
+}
+
+EGLContext eglGetCurrentContext(void) {
+    return getThreadState()->context;
+}
+
+EGLSurface eglGetCurrentSurface(EGLint readdraw) {
+    return getThreadState()->surface;
+}
+
+EGLDisplay eglGetCurrentDisplay(void) {
+    return gDisplay;
+}
+
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
+    return EGL_TRUE;
+}
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) {
+    return (EGLImageKHR) malloc(sizeof(EGLImageKHR));
+}
+
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) {
+    free(image);
+    return EGL_TRUE;
+}
+
+void eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {}
diff --git a/libs/hwui/tests/nullgles.cpp b/libs/hwui/tests/nullgles.cpp
new file mode 100644
index 0000000..8ca7598
--- /dev/null
+++ b/libs/hwui/tests/nullgles.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright(C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0(the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <GLES3/gl3.h>
+#include <GLES2/gl2ext.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+struct {
+    GLboolean scissorEnabled;
+} gState;
+
+void glGenCommon(GLsizei n, GLuint *buffers) {
+    static GLuint nextId = 0;
+    int i;
+    for(i = 0; i < n; i++) {
+        buffers[i] = ++nextId;
+    }
+}
+
+void glGenBuffers(GLsizei n, GLuint *buffers) {
+    glGenCommon(n, buffers);
+}
+
+void glGenFramebuffers(GLsizei n, GLuint *framebuffers) {
+    glGenCommon(n, framebuffers);
+}
+
+void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers) {
+    glGenCommon(n, renderbuffers);
+}
+
+void glGenTextures(GLsizei n, GLuint *textures) {
+    glGenCommon(n, textures);
+}
+
+GLuint glCreateProgram(void) {
+    static GLuint nextProgram = 0;
+    return ++nextProgram;
+}
+
+GLuint glCreateShader(GLenum type) {
+    static GLuint nextShader = 0;
+    return ++nextShader;
+}
+
+void glGetProgramiv(GLuint program, GLenum pname, GLint *params) {
+    switch (pname) {
+    case GL_DELETE_STATUS:
+    case GL_LINK_STATUS:
+    case GL_VALIDATE_STATUS:
+        *params = GL_TRUE;
+        break;
+    case GL_INFO_LOG_LENGTH:
+        *params = 16;
+        break;
+    }
+}
+
+void glGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+    *length = snprintf(infoLog, bufSize, "success");
+    if (*length >= bufSize) {
+        *length = bufSize - 1;
+    }
+}
+
+void glGetShaderiv(GLuint shader, GLenum pname, GLint *params) {
+    switch (pname) {
+    case GL_COMPILE_STATUS:
+    case GL_DELETE_STATUS:
+        *params = GL_TRUE;
+    }
+}
+
+void glGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+    *length = snprintf(infoLog, bufSize, "success");
+    if (*length >= bufSize) {
+        *length = bufSize - 1;
+    }
+}
+
+void setBooleanState(GLenum cap, GLboolean value) {
+    switch (cap) {
+    case GL_SCISSOR_TEST:
+        gState.scissorEnabled = value;
+        break;
+    }
+}
+
+void glEnable(GLenum cap) {
+    setBooleanState(cap, GL_TRUE);
+}
+
+void glDisable(GLenum cap) {
+    setBooleanState(cap, GL_FALSE);
+}
+
+GLboolean glIsEnabled(GLenum cap) {
+    switch (cap) {
+    case GL_SCISSOR_TEST:
+        return gState.scissorEnabled;
+    default:
+        return GL_FALSE;
+    }
+}
+
+void glGetIntegerv(GLenum pname, GLint *data) {
+    switch (pname) {
+    case GL_MAX_TEXTURE_SIZE:
+        *data = 2048;
+        break;
+    case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+        *data = 4;
+        break;
+    default:
+        *data = 0;
+    }
+}
+
+const char* getString(GLenum name) {
+    switch (name) {
+    case GL_VENDOR:
+        return "android";
+    case GL_RENDERER:
+        return "null";
+    case GL_VERSION:
+        return "OpenGL ES 2.0 rev1";
+    case GL_SHADING_LANGUAGE_VERSION:
+        return "OpenGL ES GLSL ES 2.0 rev1";
+    case GL_EXTENSIONS:
+    default:
+        return "";
+    }
+}
+
+const GLubyte* glGetString(GLenum name) {
+    return (GLubyte*) getString(name);
+}
+
+void glActiveTexture(GLenum texture) {}
+void glAttachShader(GLuint program, GLuint shader) {}
+void glBindAttribLocation(GLuint program, GLuint index, const GLchar *name) {}
+void glBindBuffer(GLenum target, GLuint buffer) {}
+void glBindFramebuffer(GLenum target, GLuint framebuffer) {}
+void glBindRenderbuffer(GLenum target, GLuint renderbuffer) {}
+void glBindTexture(GLenum target, GLuint texture) {}
+void glBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {}
+void glBlendEquation(GLenum mode) {}
+void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {}
+void glBlendFunc(GLenum sfactor, GLenum dfactor) {}
+void glBlendFuncSeparate(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) {}
+void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {}
+void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) {}
+void glClear(GLbitfield mask) {}
+void glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {}
+void glClearDepthf(GLfloat d) {}
+void glClearStencil(GLint s) {}
+void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {}
+void glCompileShader(GLuint shader) {}
+void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) {}
+void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) {}
+void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {}
+void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {}
+void glCullFace(GLenum mode) {}
+void glDeleteBuffers(GLsizei n, const GLuint *buffers) {}
+void glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) {}
+void glDeleteProgram(GLuint program) {}
+void glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) {}
+void glDeleteShader(GLuint shader) {}
+void glDeleteTextures(GLsizei n, const GLuint *textures) {}
+void glDepthFunc(GLenum func) {}
+void glDepthMask(GLboolean flag) {}
+void glDepthRangef(GLfloat n, GLfloat f) {}
+void glDetachShader(GLuint program, GLuint shader) {}
+void glDisableVertexAttribArray(GLuint index) {}
+void glDrawArrays(GLenum mode, GLint first, GLsizei count) {}
+void glDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) {}
+void glEnableVertexAttribArray(GLuint index) {}
+void glFinish(void) {}
+void glFlush(void) {}
+void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {}
+void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {}
+void glFrontFace(GLenum mode) {}
+void glGenerateMipmap(GLenum target) {}
+GLint glGetAttribLocation(GLuint program, const GLchar *name) { return 1; }
+GLenum glGetError(void) { return GL_NO_ERROR; }
+GLint glGetUniformLocation(GLuint program, const GLchar *name) { return 2; }
+void glHint(GLenum target, GLenum mode) {}
+void glLineWidth(GLfloat width) {}
+void glLinkProgram(GLuint program) {}
+void glPixelStorei(GLenum pname, GLint param) {}
+void glPolygonOffset(GLfloat factor, GLfloat units) {}
+void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) {}
+void glReleaseShaderCompiler(void) {}
+void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {}
+void glSampleCoverage(GLfloat value, GLboolean invert) {}
+void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {}
+void glShaderBinary(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) {}
+void glShaderSource(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) {}
+void glStencilFunc(GLenum func, GLint ref, GLuint mask) {}
+void glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {}
+void glStencilMask(GLuint mask) {}
+void glStencilMaskSeparate(GLenum face, GLuint mask) {}
+void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {}
+void glStencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {}
+void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) {}
+void glTexParameterf(GLenum target, GLenum pname, GLfloat param) {}
+void glTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) {}
+void glTexParameteri(GLenum target, GLenum pname, GLint param) {}
+void glTexParameteriv(GLenum target, GLenum pname, const GLint *params) {}
+void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) {}
+void glUniform1f(GLint location, GLfloat v0) {}
+void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform1i(GLint location, GLint v0) {}
+void glUniform1iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform2f(GLint location, GLfloat v0, GLfloat v1) {}
+void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform2i(GLint location, GLint v0, GLint v1) {}
+void glUniform2iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {}
+void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform3i(GLint location, GLint v0, GLint v1, GLint v2) {}
+void glUniform3iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {}
+void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) {}
+void glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {}
+void glUniform4iv(GLint location, GLsizei count, const GLint *value) {}
+void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {}
+void glUseProgram(GLuint program) {}
+void glValidateProgram(GLuint program) {}
+void glVertexAttrib1f(GLuint index, GLfloat x) {}
+void glVertexAttrib1fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) {}
+void glVertexAttrib2fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) {}
+void glVertexAttrib3fv(GLuint index, const GLfloat *v) {}
+void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {}
+void glVertexAttrib4fv(GLuint index, const GLfloat *v) {}
+void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) {}
+void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) {}
+
+
+// gles2 ext
+void glInsertEventMarkerEXT(GLsizei length, const GLchar *marker) {}
+void glPushGroupMarkerEXT(GLsizei length, const GLchar *marker) {}
+void glPopGroupMarkerEXT(void) {}
+void glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments) {}
+void glStartTilingQCOM(GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask) {}
+void glEndTilingQCOM(GLbitfield preserveMask) {}
+void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) {}
+
+// GLES3
+void* glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) {
+    return 0;
+}
+
+GLboolean glUnmapBuffer(GLenum target) {
+    return GL_FALSE;
+}
diff --git a/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml b/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml
new file mode 100644
index 0000000..28d2e26
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_dnd_off.xml
@@ -0,0 +1,41 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:alpha=".3"
+    android:width="64dp" >
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M13.8,11.1L17.0,11.1l0.0,2.0l-1.2,0.0l4.5,4.5c1.1,-1.6 1.7,-3.5 1.7,-5.5c0.0,-5.5 -4.5,-10.0 -10.0,-10.0c-2.0,0.0 -3.9,0.6 -5.5,1.7L13.8,11.1z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M13.0,13.1L7.0,13.1l0.0,-2.0l4.0,0.0L4.9,5.0C3.1,6.8 2.0,9.3 2.0,12.1c0.0,5.5 4.5,10.0 10.0,10.0c2.8,0.0 5.3,-1.1 7.1,-2.9L13.0,13.1z" />
+
+    <group
+        android:pivotX="12.0"
+        android:pivotY="12.0"
+        android:rotation="45.0"
+        android:translateX="0.5"
+        android:translateY="0.5" >
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M-2.8,11.8l28.3,0.0l0.0,2.0l-28.3,0.0z" />
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml b/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml
new file mode 100644
index 0000000..7617ec4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_dnd_on.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="64dp"
+        android:height="64dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M24.0,4.0C12.95,4.0 4.0,12.95 4.0,24.0s8.95,20.0 20.0,20.0 20.0,-8.95 20.0,-20.0S35.05,4.0 24.0,4.0zm10.0,22.0L14.0,26.0l0.0,-4.0l20.0,0.0l0.0,4.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_dnd.xml b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
new file mode 100644
index 0000000..9361bc0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
@@ -0,0 +1,28 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetLeft="2.5dp"
+    android:insetRight="2.5dp">
+    <vector
+            android:width="17dp"
+            android:height="17dp"
+            android:viewportWidth="48.0"
+            android:viewportHeight="48.0">
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M24.0,4.0C12.95,4.0 4.0,12.95 4.0,24.0s8.95,20.0 20.0,20.0 20.0,-8.95 20.0,-20.0S35.05,4.0 24.0,4.0zm10.0,22.0L14.0,26.0l0.0,-4.0l20.0,0.0l0.0,4.0z"/>
+    </vector>
+</inset>
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
index 27353ff..33c1899 100644
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -40,6 +40,16 @@
             android:clipChildren="false" />
     </FrameLayout>
 
+    <View
+        android:id="@+id/zen_embedded_divider"
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:visibility="gone"
+        android:layout_marginStart="@dimen/qs_panel_padding"
+        android:layout_marginEnd="@dimen/qs_panel_padding"
+        android:layout_marginBottom="@dimen/qs_panel_padding"
+        android:background="#4dffffff" />
+
     <RelativeLayout
         android:id="@+id/zen_subhead"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 8a73fca..2e9e9f7 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -118,7 +118,7 @@
 
     <!-- The default tiles to display in QuickSettings -->
     <string name="quick_settings_tiles_default" translatable="false">
-        wifi,bt,inversion,cell,airplane,rotation,flashlight,location,cast,hotspot
+        wifi,bt,inversion,dnd,cell,airplane,rotation,flashlight,location,cast,hotspot
     </string>
 
     <!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d8b6a82..1b1b525 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -430,6 +430,16 @@
     <string name="accessibility_quick_settings_airplane_changed_off">Airplane mode turned off.</string>
     <!-- Announcement made when the airplane mode changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_airplane_changed_on">Airplane mode turned on.</string>
+    <!-- Content description of the do not disturb tile in quick settings when on in priority (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_priority_on">Do not disturb on, priority only.</string>
+    <!-- Content description of the do not disturb tile in quick settings when on in none (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_none_on">Do not disturb on, no interruptions.</string>
+     <!-- Content description of the do not disturb tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_off">Do not disturb off.</string>
+    <!-- Announcement made when do not disturb changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_changed_off">Do not disturb turned off.</string>
+    <!-- Announcement made when do not disturb changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_changed_on">Do not disturb turned on.</string>
     <!-- Content description of the bluetooth tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_bluetooth_off">Bluetooth off.</string>
     <!-- Content description of the bluetooth tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -554,6 +564,12 @@
 
     <!-- QuickSettings: Airplane mode [CHAR LIMIT=NONE] -->
     <string name="quick_settings_airplane_mode_label">Airplane mode</string>
+    <!-- QuickSettings: Do not disturb [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_dnd_label">Do not disturb</string>
+    <!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_dnd_priority_label">Priority only</string>
+    <!-- QuickSettings: Do not disturb - No interruptions [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_dnd_none_label">No interruptions</string>
     <!-- QuickSettings: Bluetooth [CHAR LIMIT=NONE] -->
     <string name="quick_settings_bluetooth_label">Bluetooth</string>
     <!-- QuickSettings: Bluetooth (Multiple) [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 4dacacf..7f944f0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -253,12 +253,6 @@
             @Override
             public void onStateChanged(QSTile.State state) {
                 int visibility = state.visible ? VISIBLE : GONE;
-                if (state.visible && !mGridContentVisible) {
-
-                    // We don't want to show it if the content is hidden,
-                    // then we just set it to invisible, to ensure that it gets visible again
-                    visibility = INVISIBLE;
-                }
                 setTileVisibility(r.tileView, visibility);
                 r.tileView.onStateChanged(state);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
new file mode 100644
index 0000000..79600f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.qs.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.ZenModePanel;
+
+/** Quick settings tile: Do not disturb **/
+public class DndTile extends QSTile<QSTile.BooleanState> {
+    private static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+
+    private static final String ACTION_SET_VISIBLE = "com.android.systemui.dndtile.SET_VISIBLE";
+    private static final String EXTRA_VISIBLE = "visible";
+    private static final String PREF_KEY_VISIBLE = "DndTileVisible";
+
+    private final ZenModeController mController;
+    private final DndDetailAdapter mDetailAdapter;
+
+    private boolean mListening;
+    private boolean mVisible;
+    private boolean mShowingDetail;
+
+    public DndTile(Host host) {
+        super(host);
+        mController = host.getZenModeController();
+        mDetailAdapter = new DndDetailAdapter();
+        mVisible = getSharedPrefs(mContext).getBoolean(PREF_KEY_VISIBLE, false);
+        mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
+    }
+
+    public static void setVisible(Context context, boolean visible) {
+        context.sendBroadcast(new Intent(DndTile.ACTION_SET_VISIBLE)
+                .putExtra(DndTile.EXTRA_VISIBLE, visible));
+    }
+
+    public static boolean isVisible(Context context) {
+        return getSharedPrefs(context).getBoolean(PREF_KEY_VISIBLE, false);
+    }
+
+    @Override
+    public DetailAdapter getDetailAdapter() {
+        return mDetailAdapter;
+    }
+
+    @Override
+    protected BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void handleClick() {
+        if (mState.value) {
+            mController.setZen(Global.ZEN_MODE_OFF);
+        } else {
+            mController.setZen(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+            showDetail(true);
+        }
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
+        state.value = zen != Global.ZEN_MODE_OFF;
+        state.visible = mVisible;
+        switch (zen) {
+            case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+                state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
+                state.label = mContext.getString(R.string.quick_settings_dnd_priority_label);
+                state.contentDescription = mContext.getString(
+                        R.string.accessibility_quick_settings_dnd_priority_on);
+                break;
+            case Global.ZEN_MODE_NO_INTERRUPTIONS:
+                state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
+                state.label = mContext.getString(R.string.quick_settings_dnd_none_label);
+                state.contentDescription = mContext.getString(
+                        R.string.accessibility_quick_settings_dnd_none_on);
+                break;
+            default:
+                state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_off);
+                state.label = mContext.getString(R.string.quick_settings_dnd_label);
+                state.contentDescription =  mContext.getString(
+                        R.string.accessibility_quick_settings_dnd_off);
+                break;
+        }
+        if (mShowingDetail && !state.value) {
+            showDetail(false);
+        }
+    }
+
+    @Override
+    protected String composeChangeAnnouncement() {
+        if (mState.value) {
+            return mContext.getString(R.string.accessibility_quick_settings_dnd_changed_on);
+        } else {
+            return mContext.getString(R.string.accessibility_quick_settings_dnd_changed_off);
+        }
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        if (mListening == listening) return;
+        mListening = listening;
+        if (mListening) {
+            mController.addCallback(mZenCallback);
+        } else {
+            mController.removeCallback(mZenCallback);
+        }
+    }
+
+    private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
+        public void onZenChanged(int zen) {
+            refreshState(zen);
+        }
+    };
+
+    private static SharedPreferences getSharedPrefs(Context context) {
+        return context.getSharedPreferences(context.getPackageName(), 0);
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mVisible = intent.getBooleanExtra(EXTRA_VISIBLE, false);
+            getSharedPrefs(mContext).edit().putBoolean(PREF_KEY_VISIBLE, mVisible).commit();
+            refreshState();
+        }
+    };
+
+    private final class DndDetailAdapter implements DetailAdapter, OnAttachStateChangeListener {
+
+        @Override
+        public int getTitle() {
+            return R.string.quick_settings_dnd_label;
+        }
+
+        @Override
+        public Boolean getToggleState() {
+            return mState.value;
+        }
+
+        @Override
+        public Intent getSettingsIntent() {
+            return ZEN_SETTINGS;
+        }
+
+        @Override
+        public void setToggleState(boolean state) {
+            if (!state) {
+                mController.setZen(Global.ZEN_MODE_OFF);
+                showDetail(false);
+            }
+        }
+
+        @Override
+        public View createDetailView(Context context, View convertView, ViewGroup parent) {
+            final ZenModePanel zmp = convertView != null ? (ZenModePanel) convertView
+                    : (ZenModePanel) LayoutInflater.from(context).inflate(
+                            R.layout.zen_mode_panel, parent, false);
+            if (convertView == null) {
+                zmp.init(mController);
+                zmp.setEmbedded(true);
+                zmp.addOnAttachStateChangeListener(this);
+            }
+            return zmp;
+        }
+
+        @Override
+        public void onViewAttachedToWindow(View v) {
+            mShowingDetail = true;
+        }
+
+        @Override
+        public void onViewDetachedFromWindow(View v) {
+            mShowingDetail = false;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index e8a000c..5da8457 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -33,6 +33,7 @@
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.systemui.R;
+import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.CastController.CastDevice;
 import com.android.systemui.statusbar.policy.HotspotController;
@@ -198,7 +199,11 @@
         int volumeIconId = 0;
         String volumeDescription = null;
 
-        if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
+        if (DndTile.isVisible(mContext)) {
+            zenVisible = mZen != Global.ZEN_MODE_OFF;
+            zenIconId = R.drawable.stat_sys_dnd;
+            zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
+        } else if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
             zenVisible = true;
             zenIconId = R.drawable.stat_sys_zen_none;
             zenDescription = mContext.getString(R.string.zen_no_interruptions);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 45a1386..954eb10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -41,6 +41,7 @@
 import com.android.systemui.qs.tiles.LocationTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.qs.tiles.WifiTile;
+import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CastController;
@@ -256,6 +257,7 @@
         else if (tileSpec.equals("inversion")) return new ColorInversionTile(this);
         else if (tileSpec.equals("cell")) return new CellularTile(this);
         else if (tileSpec.equals("airplane")) return new AirplaneModeTile(this);
+        else if (tileSpec.equals("dnd")) return new DndTile(this);
         else if (tileSpec.equals("rotation")) return new RotationLockTile(this);
         else if (tileSpec.equals("flashlight")) return new FlashlightTile(this);
         else if (tileSpec.equals("location")) return new LocationTile(this);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 8048a48..97ebbf1 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -44,6 +44,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.statusbar.ServiceMonitor;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
@@ -114,6 +115,7 @@
             if (LOGD) Log.d(TAG, "Registering volume controller");
             mAudioManager.setVolumeController(mVolumeController);
             mMediaSessionManager.setRemoteVolumeController(mRemoteVolumeController);
+            DndTile.setVisible(mContext, false);
         } else {
             if (LOGD) Log.d(TAG, "Unregistering volume controller");
             mAudioManager.setVolumeController(null);
@@ -322,7 +324,8 @@
                             .setContentTitle(mContext.getString(
                                     R.string.volumeui_notification_title, getAppLabel(component)))
                             .setContentText(mContext.getString(R.string.volumeui_notification_text))
-                            .setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent, 0))
+                            .setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent,
+                                    PendingIntent.FLAG_UPDATE_CURRENT))
                             .setPriority(Notification.PRIORITY_MIN)
                             .setVisibility(Notification.VISIBILITY_PUBLIC)
                             .setColor(mContext.getResources().getColor(
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 5726fa7..6cecc8f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -90,9 +90,11 @@
     private String mTag = TAG + "/" + Integer.toHexString(System.identityHashCode(this));
 
     private SegmentedButtons mZenButtons;
+    private ViewGroup mZenButtonsContainer;
     private View mZenSubhead;
     private TextView mZenSubheadCollapsed;
     private TextView mZenSubheadExpanded;
+    private View mZenEmbeddedDivider;
     private View mMoreSettings;
     private LinearLayout mZenConditions;
 
@@ -114,6 +116,7 @@
     private Condition mSessionExitCondition;
     private Condition[] mConditions;
     private Condition mTimeCondition;
+    private boolean mEmbedded;
 
     public ZenModePanel(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -140,9 +143,25 @@
         pw.print("  mExpanded="); pw.println(mExpanded);
         pw.print("  mSessionZen="); pw.println(mSessionZen);
         pw.print("  mAttachedZen="); pw.println(mAttachedZen);
+        pw.print("  mEmbedded="); pw.println(mEmbedded);
         mTransitionHelper.dump(fd, pw, args);
     }
 
+    public void setEmbedded(boolean embedded) {
+        if (mEmbedded == embedded) return;
+        mEmbedded = embedded;
+        mZenButtonsContainer.setLayoutTransition(mEmbedded ? null : newLayoutTransition(null));
+        if (mEmbedded) {
+            mZenButtonsContainer.setBackground(null);
+        } else {
+            mZenButtonsContainer.setBackgroundResource(R.drawable.qs_background_secondary);
+        }
+        mZenButtons.getChildAt(2).setVisibility(mEmbedded ? GONE : VISIBLE);
+        mZenEmbeddedDivider.setVisibility(mEmbedded ? VISIBLE : GONE);
+        setExpanded(mEmbedded);
+        updateWidgets();
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -156,10 +175,11 @@
                 Global.ZEN_MODE_OFF);
         mZenButtons.setCallback(mZenButtonsCallback);
 
-        final ViewGroup zenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
-        zenButtonsContainer.setLayoutTransition(newLayoutTransition(null));
+        mZenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
+        mZenButtonsContainer.setLayoutTransition(newLayoutTransition(null));
 
         mZenSubhead = findViewById(R.id.zen_subhead);
+        mZenEmbeddedDivider = findViewById(R.id.zen_embedded_divider);
 
         mZenSubheadCollapsed = (TextView) findViewById(R.id.zen_subhead_collapsed);
         mZenSubheadCollapsed.setOnClickListener(new View.OnClickListener() {
@@ -222,7 +242,9 @@
         mAttachedZen = -1;
         mSessionZen = -1;
         setSessionExitCondition(null);
-        setExpanded(false);
+        if (!mEmbedded) {
+            setExpanded(false);
+        }
         setRequestingConditions(false);
         mTransitionHelper.clear();
     }
@@ -361,7 +383,7 @@
 
     private void handleUpdateZen(int zen) {
         if (mSessionZen != -1 && mSessionZen != zen) {
-            setExpanded(zen != Global.ZEN_MODE_OFF);
+            setExpanded(mEmbedded || zen != Global.ZEN_MODE_OFF);
             mSessionZen = zen;
         }
         mZenButtons.setSelectedValue(zen);
@@ -403,7 +425,7 @@
         final boolean expanded = !mHidden && mExpanded;
 
         mZenButtons.setVisibility(mHidden ? GONE : VISIBLE);
-        mZenSubhead.setVisibility(!mHidden && !zenOff ? VISIBLE : GONE);
+        mZenSubhead.setVisibility(!mHidden && !zenOff && !mEmbedded ? VISIBLE : GONE);
         mZenSubheadExpanded.setVisibility(expanded ? VISIBLE : GONE);
         mZenSubheadCollapsed.setVisibility(!expanded ? VISIBLE : GONE);
         mMoreSettings.setVisibility(zenImportant && expanded ? VISIBLE : GONE);
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 8d7a182..376ef2a 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -736,50 +736,47 @@
     }
 
     public void notifySignalStrengthForSubscriber(int subId, SignalStrength signalStrength) {
+        log("notifySignalStrengthForSubscriber: subId=" + subId
+                + " signalStrength=" + signalStrength);
         if (!checkNotifyPermission("notifySignalStrength()")) {
+            log("notifySignalStrengthForSubscriber: permission check failure");
             return;
         }
-        if (VDBG) {
-            log("notifySignalStrengthForSubscriber: subId=" + subId
-                + " signalStrength=" + signalStrength);
-            toStringLogSSC("notifySignalStrengthForSubscriber");
-        }
+        toStringLogSSC("notifySignalStrengthForSubscriber");
         synchronized (mRecords) {
             int phoneId = SubscriptionManager.getPhoneId(subId);
             if (validatePhoneId(phoneId)) {
-                if (VDBG) log("notifySignalStrengthForSubscriber: valid phoneId=" + phoneId);
+                log("notifySignalStrengthForSubscriber: valid phoneId=" + phoneId);
                 mSignalStrength[phoneId] = signalStrength;
                 for (Record r : mRecords) {
-                    if (VDBG) {
-                        log("notifySignalStrengthForSubscriber: r=" + r + " subId=" + subId
-                                + " phoneId=" + phoneId + " ss=" + signalStrength);
-                    }
+                    log("notifySignalStrengthForSubscriber: r=" + r + " subId=" + subId
+                            + " phoneId=" + phoneId + " ss=" + signalStrength);
                     if (r.matchPhoneStateListenerEvent(
                                 PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) &&
                             idMatch(r.subId, subId, phoneId)) {
                         try {
-                            if (DBG) {
-                                log("notifySignalStrengthForSubscriber: callback.onSsS r=" + r
-                                        + " subId=" + subId + " phoneId=" + phoneId
-                                        + " ss=" + signalStrength);
-                            }
+                            log("notifySignalStrengthForSubscriber: callback.onSsS r=" + r
+                                    + " subId=" + subId + " phoneId=" + phoneId
+                                    + " ss=" + signalStrength);
                             r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength));
                         } catch (RemoteException ex) {
+                            log("notifySignalStrengthForSubscriber: Exception while calling callback!!");
                             mRemoveList.add(r.binder);
                         }
+                    } else {
+                        log("notifySignalStrengthForSubscriber: no match for LISTEN_SIGNAL_STRENGTHS");
                     }
                     if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTH) &&
                             idMatch(r.subId, subId, phoneId)){
                         try {
                             int gsmSignalStrength = signalStrength.getGsmSignalStrength();
                             int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
-                            if (DBG) {
-                                log("notifySignalStrengthForSubscriber: callback.onSS r=" + r
-                                        + " subId=" + subId + " phoneId=" + phoneId
-                                        + " gsmSS=" + gsmSignalStrength + " ss=" + ss);
-                            }
+                            log("notifySignalStrengthForSubscriber: callback.onSS r=" + r
+                                    + " subId=" + subId + " phoneId=" + phoneId
+                                    + " gsmSS=" + gsmSignalStrength + " ss=" + ss);
                             r.callback.onSignalStrengthChanged(ss);
                         } catch (RemoteException ex) {
+                            log("notifySignalStrengthForSubscriber: Exception in deprecated LISTEN_SIGNAL_STRENGTH");
                             mRemoveList.add(r.binder);
                         }
                     }
@@ -787,6 +784,7 @@
             } else {
                 log("notifySignalStrengthForSubscriber: invalid phoneId=" + phoneId);
             }
+            log("notifySignalStrengthForSubscriber: done with all records");
             handleRemoveListLocked();
         }
         broadcastSignalStrengthChanged(signalStrength, subId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 966dc88..008d718 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2398,8 +2398,7 @@
             } else {
                 finishRunningVoiceLocked();
             }
-            mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity");
-            if (r != null) {
+            if (r != null && mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
                 mWindowManager.setFocusedApp(r.appToken, true);
             }
             applyUpdateLockStateLocked(r);
@@ -2423,6 +2422,7 @@
                 ActivityRecord r = stack.topRunningActivityLocked(null);
                 if (r != null) {
                     setFocusedActivityLocked(r, "setFocusedStack");
+                    mStackSupervisor.resumeTopActivitiesLocked(stack, null, null);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index c0d2502..0cbc9d7 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -479,10 +479,16 @@
 
             AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
                     realTheme, com.android.internal.R.styleable.Window, userId);
+            final boolean translucent = ent.array.getBoolean(
+                    com.android.internal.R.styleable.Window_windowIsTranslucent, false)
+                    || (!ent.array.hasValue(
+                            com.android.internal.R.styleable.Window_windowIsTranslucent)
+                            && ent.array.getBoolean(
+                                    com.android.internal.R.styleable.Window_windowSwipeToDismiss,
+                                            false));
             fullscreen = ent != null && !ent.array.getBoolean(
                     com.android.internal.R.styleable.Window_windowIsFloating, false)
-                    && !ent.array.getBoolean(
-                    com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+                    && !translucent;
             noDisplay = ent != null && ent.array.getBoolean(
                     com.android.internal.R.styleable.Window_windowNoDisplay, false);
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index c3343f5..40a8b86 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -496,11 +496,20 @@
 
     final void moveToFront(String reason) {
         if (isAttached()) {
-            if (isOnHomeDisplay()) {
-                mStackSupervisor.moveHomeStack(isHomeStack(), reason);
+            final boolean homeStack = isHomeStack()
+                    || (mActivityContainer.mParentActivity != null
+                        && mActivityContainer.mParentActivity.isHomeActivity());
+            ActivityStack lastFocusStack = null;
+            if (!homeStack) {
+                // Need to move this stack to the front before calling
+                // {@link ActivityStackSupervisor#moveHomeStack} below.
+                lastFocusStack = mStacks.get(mStacks.size() - 1);
+                mStacks.remove(this);
+                mStacks.add(this);
             }
-            mStacks.remove(this);
-            mStacks.add(this);
+            if (isOnHomeDisplay()) {
+                mStackSupervisor.moveHomeStack(homeStack, reason, lastFocusStack);
+            }
             final TaskRecord task = topTask();
             if (task != null) {
                 mWindowManager.moveTaskToTop(task.taskId);
@@ -2580,7 +2589,6 @@
         if (top == null) {
             return false;
         }
-        stack.moveToFront(myReason);
         mService.setFocusedActivityLocked(top, myReason);
         return true;
     }
@@ -3656,8 +3664,7 @@
             }
         }
 
-        if (DEBUG_TRANSITION) Slog.v(TAG,
-                "Prepare to back transition: task=" + taskId);
+        if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to back transition: task=" + taskId);
 
         boolean prevIsHome = false;
         if (tr.isOverHomeStack()) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 907381e..c4234eb 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -386,21 +386,22 @@
         return mLastFocusedStack;
     }
 
-    /** Top of all visible stacks. Use {@link ActivityStack#isStackVisibleLocked} to determine if a
-     * specific stack is visible or not. */
+    /** Top of all visible stacks is/should always be equal to the focused stack.
+     * Use {@link ActivityStack#isStackVisibleLocked} to determine if a specific
+     * stack is visible or not. */
     boolean isFrontStack(ActivityStack stack) {
         final ActivityRecord parent = stack.mActivityContainer.mParentActivity;
         if (parent != null) {
             stack = parent.task.stack;
         }
-        ArrayList<ActivityStack> stacks = stack.mStacks;
-        if (stacks != null && !stacks.isEmpty()) {
-            return stack == stacks.get(stacks.size() - 1);
-        }
-        return false;
+        return stack == mFocusedStack;
     }
 
     void moveHomeStack(boolean toFront, String reason) {
+        moveHomeStack(toFront, reason, null);
+    }
+
+    void moveHomeStack(boolean toFront, String reason, ActivityStack lastFocusedStack) {
         ArrayList<ActivityStack> stacks = mHomeStack.mStacks;
         final int topNdx = stacks.size() - 1;
         if (topNdx <= 0) {
@@ -409,13 +410,17 @@
         ActivityStack topStack = stacks.get(topNdx);
         final boolean homeInFront = topStack == mHomeStack;
         if (homeInFront != toFront) {
-            mLastFocusedStack = topStack;
             stacks.remove(mHomeStack);
             stacks.add(toFront ? topNdx : 0, mHomeStack);
-            mFocusedStack = stacks.get(topNdx);
             if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: topStack old=" + topStack + " new="
                     + mFocusedStack);
         }
+
+        if (lastFocusedStack != null) {
+            mLastFocusedStack = lastFocusedStack;
+        }
+        mFocusedStack = stacks.get(topNdx);
+
         EventLog.writeEvent(EventLogTags.AM_HOME_STACK_MOVED,
                 mCurrentUser, toFront ? 1 : 0, stacks.get(topNdx).getStackId(),
                 mFocusedStack == null ? -1 : mFocusedStack.getStackId(), reason);
@@ -1541,25 +1546,27 @@
         return err;
     }
 
-    ActivityStack adjustStackFocus(ActivityRecord r, boolean newTask) {
+    ActivityStack computeStackFocus(ActivityRecord r, boolean newTask) {
         final TaskRecord task = r.task;
 
         // On leanback only devices we should keep all activities in the same stack.
         if (!mLeanbackOnlyDevice &&
                 (r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
+
+            ActivityStack stack;
+
             if (task != null) {
-                final ActivityStack taskStack = task.stack;
-                if (taskStack.isOnHomeDisplay()) {
-                    if (mFocusedStack != taskStack) {
-                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Setting " +
+                stack = task.stack;
+                if (stack.isOnHomeDisplay()) {
+                    if (mFocusedStack != stack) {
+                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "computeStackFocus: Setting " +
                                 "focused stack to r=" + r + " task=" + task);
-                        mFocusedStack = taskStack;
                     } else {
                         if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
-                            "adjustStackFocus: Focused stack already=" + mFocusedStack);
+                            "computeStackFocus: Focused stack already=" + mFocusedStack);
                     }
                 }
-                return taskStack;
+                return stack;
             }
 
             final ActivityContainer container = r.mInitialActivityContainer;
@@ -1572,43 +1579,41 @@
             if (mFocusedStack != mHomeStack && (!newTask ||
                     mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
                 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
-                        "adjustStackFocus: Have a focused stack=" + mFocusedStack);
+                        "computeStackFocus: Have a focused stack=" + mFocusedStack);
                 return mFocusedStack;
             }
 
             final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
             for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = homeDisplayStacks.get(stackNdx);
+                stack = homeDisplayStacks.get(stackNdx);
                 if (!stack.isHomeStack()) {
                     if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
-                            "adjustStackFocus: Setting focused stack=" + stack);
-                    mFocusedStack = stack;
-                    return mFocusedStack;
+                            "computeStackFocus: Setting focused stack=" + stack);
+                    return stack;
                 }
             }
 
             // Need to create an app stack for this user.
-            mFocusedStack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
-            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r +
-                    " stackId=" + mFocusedStack.mStackId);
-            return mFocusedStack;
+            stack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
+            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "computeStackFocus: New stack r=" + r +
+                    " stackId=" + stack.mStackId);
+            return stack;
         }
         return mHomeStack;
     }
 
-    void setFocusedStack(ActivityRecord r, String reason) {
-        if (r != null) {
-            final TaskRecord task = r.task;
-            boolean isHomeActivity = !r.isApplicationActivity();
-            if (!isHomeActivity && task != null) {
-                isHomeActivity = !task.isApplicationTask();
-            }
-            if (!isHomeActivity && task != null) {
-                final ActivityRecord parent = task.stack.mActivityContainer.mParentActivity;
-                isHomeActivity = parent != null && parent.isHomeActivity();
-            }
-            moveHomeStack(isHomeActivity, reason);
+    boolean setFocusedStack(ActivityRecord r, String reason) {
+        if (r == null) {
+            // Not sure what you are trying to do, but it is not going to work...
+            return false;
         }
+        final TaskRecord task = r.task;
+        if (task == null || task.stack == null) {
+            Slog.w(TAG, "Can't set focus stack for r=" + r + " task=" + task);
+            return false;
+        }
+        task.stack.moveToFront(reason);
+        return true;
     }
 
     final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
@@ -2082,10 +2087,9 @@
                 return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
             }
             newTask = true;
-            targetStack = adjustStackFocus(r, newTask);
-            if (!launchTaskBehind) {
-                targetStack.moveToFront("startingNewTask");
-            }
+            targetStack = computeStackFocus(r, newTask);
+            targetStack.moveToFront("startingNewTask");
+
             if (reuseTask == null) {
                 r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                         newTaskInfo != null ? newTaskInfo : r.info,
@@ -2206,7 +2210,7 @@
             // This not being started from an existing activity, and not part
             // of a new task...  just put it in the top task, though these days
             // this case should never happen.
-            targetStack = adjustStackFocus(r, newTask);
+            targetStack = computeStackFocus(r, newTask);
             targetStack.moveToFront("addingToTopTask");
             ActivityRecord prev = targetStack.topActivity();
             r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(),
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index afe7d7a..473f5db 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1425,6 +1425,7 @@
 
     private void sendBroadcastToAll(Intent intent) {
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         final long ident = Binder.clearCallingIdentity();
         try {
             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
@@ -1434,6 +1435,7 @@
     }
 
     private void sendStickyBroadcastToAll(Intent intent) {
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         final long ident = Binder.clearCallingIdentity();
         try {
             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 09dc477..5f0ad9f 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -46,7 +46,6 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.text.TextUtils;
-import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
@@ -832,6 +831,24 @@
         }
     }
 
+    private void setDisplayOffsetsInternal(int displayId, int x, int y) {
+        synchronized (mSyncRoot) {
+            LogicalDisplay display = mLogicalDisplays.get(displayId);
+            if (display == null) {
+                return;
+            }
+            if (display.getDisplayOffsetXLocked() != x
+                    || display.getDisplayOffsetYLocked() != y) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Display " + displayId + " burn-in offset set to ("
+                            + x + ", " + y + ")");
+                }
+                display.setDisplayOffsetsLocked(x, y);
+                scheduleTraversalLocked(false);
+            }
+        }
+    }
+
     private void clearViewportsLocked() {
         mDefaultViewport.valid = false;
         mExternalTouchViewport.valid = false;
@@ -1513,5 +1530,10 @@
                 float requestedRefreshRate, boolean inTraversal) {
             setDisplayPropertiesInternal(displayId, hasContent, requestedRefreshRate, inTraversal);
         }
+
+        @Override
+        public void setDisplayOffsets(int displayId, int x, int y) {
+            setDisplayOffsetsInternal(displayId, x, y);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 6c57eec..3bb7818 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -76,6 +76,10 @@
     // The pending requested refresh rate. 0 if no request is pending.
     private float mRequestedRefreshRate;
 
+    // The display offsets to apply to the display projection.
+    private int mDisplayOffsetX;
+    private int mDisplayOffsetY;
+
     // Temporary rectangle used when needed.
     private final Rect mTempLayerStackRect = new Rect();
     private final Rect mTempDisplayRect = new Rect();
@@ -313,6 +317,10 @@
         mTempDisplayRect.set(displayRectLeft, displayRectTop,
                 displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
 
+        mTempDisplayRect.left += mDisplayOffsetX;
+        mTempDisplayRect.right += mDisplayOffsetX;
+        mTempDisplayRect.top += mDisplayOffsetY;
+        mTempDisplayRect.bottom += mDisplayOffsetY;
         device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
     }
 
@@ -356,10 +364,34 @@
         return mRequestedRefreshRate;
     }
 
+    /**
+     * Gets the burn-in offset in X.
+     */
+    public int getDisplayOffsetXLocked() {
+        return mDisplayOffsetX;
+    }
+
+    /**
+     * Gets the burn-in offset in Y.
+     */
+    public int getDisplayOffsetYLocked() {
+        return mDisplayOffsetY;
+    }
+
+    /**
+     * Sets the burn-in offsets.
+     */
+    public void setDisplayOffsetsLocked(int x, int y) {
+        mDisplayOffsetX = x;
+        mDisplayOffsetY = y;
+    }
+
     public void dumpLocked(PrintWriter pw) {
         pw.println("mDisplayId=" + mDisplayId);
         pw.println("mLayerStack=" + mLayerStack);
         pw.println("mHasContent=" + mHasContent);
+        pw.println("mRequestedRefreshRate=" + mRequestedRefreshRate);
+        pw.println("mDisplayOffset=(" + mDisplayOffsetX + ", " + mDisplayOffsetY + ")");
         pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?
                 mPrimaryDisplayDevice.getNameLocked() : "null"));
         pw.println("mBaseDisplayInfo=" + mBaseDisplayInfo);
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
new file mode 100644
index 0000000..79e7a20
--- /dev/null
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import dalvik.system.VMRuntime;
+
+/**
+ * Provides various methods for obtaining and converting of instruction sets.
+ *
+ * @hide
+ */
+public class InstructionSets {
+    private static final String PREFERRED_INSTRUCTION_SET =
+            VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);;
+    public static String[] getAppDexInstructionSets(ApplicationInfo info) {
+        if (info.primaryCpuAbi != null) {
+            if (info.secondaryCpuAbi != null) {
+                return new String[] {
+                        VMRuntime.getInstructionSet(info.primaryCpuAbi),
+                        VMRuntime.getInstructionSet(info.secondaryCpuAbi) };
+            } else {
+                return new String[] {
+                        VMRuntime.getInstructionSet(info.primaryCpuAbi) };
+            }
+        }
+
+        return new String[] { getPreferredInstructionSet() };
+    }
+
+    public static String[] getAppDexInstructionSets(PackageSetting ps) {
+        if (ps.primaryCpuAbiString != null) {
+            if (ps.secondaryCpuAbiString != null) {
+                return new String[] {
+                        VMRuntime.getInstructionSet(ps.primaryCpuAbiString),
+                        VMRuntime.getInstructionSet(ps.secondaryCpuAbiString) };
+            } else {
+                return new String[] {
+                        VMRuntime.getInstructionSet(ps.primaryCpuAbiString) };
+            }
+        }
+
+        return new String[] { getPreferredInstructionSet() };
+    }
+
+    public static String getPreferredInstructionSet() {
+        return PREFERRED_INSTRUCTION_SET;
+    }
+
+    /**
+     * Returns the instruction set that should be used to compile dex code. In the presence of
+     * a native bridge this might be different than the one shared libraries use.
+     */
+    public static String getDexCodeInstructionSet(String sharedLibraryIsa) {
+        String dexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + sharedLibraryIsa);
+        return TextUtils.isEmpty(dexCodeIsa) ? sharedLibraryIsa : dexCodeIsa;
+    }
+
+    public static String[] getDexCodeInstructionSets(String[] instructionSets) {
+        ArraySet<String> dexCodeInstructionSets = new ArraySet<String>(instructionSets.length);
+        for (String instructionSet : instructionSets) {
+            dexCodeInstructionSets.add(getDexCodeInstructionSet(instructionSet));
+        }
+        return dexCodeInstructionSets.toArray(new String[dexCodeInstructionSets.size()]);
+    }
+
+    /**
+     * Returns deduplicated list of supported instructions for dex code.
+     */
+    public static String[] getAllDexCodeInstructionSets() {
+        String[] supportedInstructionSets = new String[Build.SUPPORTED_ABIS.length];
+        for (int i = 0; i < supportedInstructionSets.length; i++) {
+            String abi = Build.SUPPORTED_ABIS[i];
+            supportedInstructionSets[i] = VMRuntime.getInstructionSet(abi);
+        }
+        return getDexCodeInstructionSets(supportedInstructionSets);
+    }
+
+    public static List<String> getAllInstructionSets() {
+        final String[] allAbis = Build.SUPPORTED_ABIS;
+        final List<String> allInstructionSets = new ArrayList<String>(allAbis.length);
+
+        for (String abi : allAbis) {
+            final String instructionSet = VMRuntime.getInstructionSet(abi);
+            if (!allInstructionSets.contains(instructionSet)) {
+                allInstructionSets.add(instructionSet);
+            }
+        }
+
+        return allInstructionSets;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
new file mode 100644
index 0000000..0a7c5cf
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageParser;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import dalvik.system.DexFile;
+import dalvik.system.StaleDexCacheError;
+
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+
+/**
+ * Helper class for running dexopt command on packages.
+ */
+final class PackageDexOptimizer {
+    static final String TAG = "PackageManager.DexOptimizer";
+    static final int DEX_OPT_SKIPPED = 0;
+    static final int DEX_OPT_PERFORMED = 1;
+    static final int DEX_OPT_DEFERRED = 2;
+    static final int DEX_OPT_FAILED = -1;
+
+    private final PackageManagerService mPackageManagerService;
+    private ArraySet<PackageParser.Package> mDeferredDexOpt;
+
+    PackageDexOptimizer(PackageManagerService packageManagerService) {
+        this.mPackageManagerService = packageManagerService;
+    }
+
+    /**
+     * Performs dexopt on all code paths and libraries of the specified package for specified
+     * instruction sets.
+     *
+     * <p>Calls to {@link com.android.server.pm.Installer#dexopt} are synchronized on
+     * {@link PackageManagerService#mInstallLock}.
+     */
+    int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
+            boolean forceDex, boolean defer, boolean inclDependencies) {
+        ArraySet<String> done;
+        if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
+            done = new ArraySet<String>();
+            done.add(pkg.packageName);
+        } else {
+            done = null;
+        }
+        synchronized (mPackageManagerService.mInstallLock) {
+            return performDexOptLI(pkg, instructionSets, forceDex, defer, done);
+        }
+    }
+
+    private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
+            boolean forceDex, boolean defer, ArraySet<String> done) {
+        final String[] instructionSets = targetInstructionSets != null ?
+                targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
+
+        if (done != null) {
+            done.add(pkg.packageName);
+            if (pkg.usesLibraries != null) {
+                performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, done);
+            }
+            if (pkg.usesOptionalLibraries != null) {
+                performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer,
+                        done);
+            }
+        }
+
+        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
+            return DEX_OPT_SKIPPED;
+        }
+
+        final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
+
+        final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
+        boolean performedDexOpt = false;
+        // There are three basic cases here:
+        // 1.) we need to dexopt, either because we are forced or it is needed
+        // 2.) we are deferring a needed dexopt
+        // 3.) we are skipping an unneeded dexopt
+        final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+        for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+            if (!forceDex && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
+                continue;
+            }
+
+            for (String path : paths) {
+                try {
+                    // This will return DEXOPT_NEEDED if we either cannot find any odex file for this
+                    // package or the one we find does not match the image checksum (i.e. it was
+                    // compiled against an old image). It will return PATCHOAT_NEEDED if we can find a
+                    // odex file and it matches the checksum of the image but not its base address,
+                    // meaning we need to move it.
+                    final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
+                            pkg.packageName, dexCodeInstructionSet, defer);
+                    if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
+                        Log.i(TAG, "Running dexopt on: " + path + " pkg="
+                                + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
+                                + " vmSafeMode=" + vmSafeMode);
+                        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+                        final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
+                                !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet,
+                                vmSafeMode);
+
+                        if (ret < 0) {
+                            // Don't bother running dexopt again if we failed, it will probably
+                            // just result in an error again. Also, don't bother dexopting for other
+                            // paths & ISAs.
+                            return DEX_OPT_FAILED;
+                        }
+
+                        performedDexOpt = true;
+                    } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
+                        Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
+                        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+                        final int ret = mPackageManagerService.mInstaller.patchoat(path, sharedGid,
+                                !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet);
+
+                        if (ret < 0) {
+                            // Don't bother running patchoat again if we failed, it will probably
+                            // just result in an error again. Also, don't bother dexopting for other
+                            // paths & ISAs.
+                            return DEX_OPT_FAILED;
+                        }
+
+                        performedDexOpt = true;
+                    }
+
+                    // We're deciding to defer a needed dexopt. Don't bother dexopting for other
+                    // paths and instruction sets. We'll deal with them all together when we process
+                    // our list of deferred dexopts.
+                    if (defer && isDexOptNeeded != DexFile.UP_TO_DATE) {
+                        addPackageForDeferredDexopt(pkg);
+                        return DEX_OPT_DEFERRED;
+                    }
+                } catch (FileNotFoundException e) {
+                    Slog.w(TAG, "Apk not found for dexopt: " + path);
+                    return DEX_OPT_FAILED;
+                } catch (IOException e) {
+                    Slog.w(TAG, "IOException reading apk: " + path, e);
+                    return DEX_OPT_FAILED;
+                } catch (StaleDexCacheError e) {
+                    Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
+                    return DEX_OPT_FAILED;
+                } catch (Exception e) {
+                    Slog.w(TAG, "Exception when doing dexopt : ", e);
+                    return DEX_OPT_FAILED;
+                }
+            }
+
+            // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
+            // either have either succeeded dexopt, or have had isDexOptNeededInternal tell us
+            // it isn't required. We therefore mark that this package doesn't need dexopt unless
+            // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
+            // it.
+            pkg.mDexOptPerformed.add(dexCodeInstructionSet);
+        }
+
+        // If we've gotten here, we're sure that no error occurred and that we haven't
+        // deferred dex-opt. We've either dex-opted one more paths or instruction sets or
+        // we've skipped all of them because they are up to date. In both cases this
+        // package doesn't need dexopt any longer.
+        return performedDexOpt ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
+    }
+
+    private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
+            boolean forceDex, boolean defer, ArraySet<String> done) {
+        for (String libName : libs) {
+            PackageParser.Package libPkg = mPackageManagerService.findSharedNonSystemLibrary(
+                    libName);
+            if (libPkg != null && !done.contains(libName)) {
+                performDexOptLI(libPkg, instructionSets, forceDex, defer, done);
+            }
+        }
+    }
+
+    /**
+     * Clears set of deferred dexopt packages.
+     * @return content of dexopt set if it was not empty
+     */
+    public ArraySet<PackageParser.Package> clearDeferredDexOptPackages() {
+        ArraySet<PackageParser.Package> result = mDeferredDexOpt;
+        mDeferredDexOpt = null;
+        return result;
+    }
+
+    public void addPackageForDeferredDexopt(PackageParser.Package pkg) {
+        if (mDeferredDexOpt == null) {
+            mDeferredDexOpt = new ArraySet<PackageParser.Package>();
+        }
+        mDeferredDexOpt.add(pkg);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c3f1418..2e2f350 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -55,6 +55,10 @@
 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.ArrayUtils.removeInt;
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
+import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
 
 import android.util.ArrayMap;
 
@@ -184,7 +188,6 @@
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.FileReader;
@@ -213,7 +216,6 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 import dalvik.system.DexFile;
-import dalvik.system.StaleDexCacheError;
 import dalvik.system.VMRuntime;
 
 import libcore.io.IoUtils;
@@ -323,13 +325,8 @@
 
     private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
 
-    private static String sPreferredInstructionSet;
-
     final ServiceThread mHandlerThread;
 
-    private static final String IDMAP_PREFIX = "/data/resource-cache/";
-    private static final String IDMAP_SUFFIX = "@idmap";
-
     final PackageHandler mHandler;
 
     /**
@@ -466,8 +463,7 @@
 
     final PackageInstallerService mInstallerService;
 
-    ArraySet<PackageParser.Package> mDeferredDexOpt = null;
-
+    private final PackageDexOptimizer mPackageDexOptimizer;
     // Cache of users who need badging.
     SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
 
@@ -1050,7 +1046,7 @@
                                         res.pkg.applicationInfo.packageName, null, updateUsers);
 
                                 // treat asec-hosted packages like removable media on upgrade
-                                if (isForwardLocked(res.pkg) || isExternal(res.pkg)) {
+                                if (res.pkg.isForwardLocked() || isExternal(res.pkg)) {
                                     if (DEBUG_INSTALL) {
                                         Slog.i(TAG, "upgrading pkg " + res.pkg
                                                 + " is ASEC-hosted -> AVAILABLE");
@@ -1338,6 +1334,7 @@
         }
 
         mInstaller = installer;
+        mPackageDexOptimizer = new PackageDexOptimizer(this);
 
         getDefaultDisplayMetrics(context, mMetrics);
 
@@ -1438,9 +1435,10 @@
                 Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
             }
 
-            final List<String> allInstructionSets = getAllInstructionSets();
+            final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();
             final String[] dexCodeInstructionSets =
-                getDexCodeInstructionSets(allInstructionSets.toArray(new String[allInstructionSets.size()]));
+                    getDexCodeInstructionSets(
+                            allInstructionSets.toArray(new String[allInstructionSets.size()]));
 
             /**
              * Ensure all external libraries have had dexopt run on them.
@@ -2335,6 +2333,19 @@
         return null;
     }
 
+    /**
+     * @hide
+     */
+    PackageParser.Package findSharedNonSystemLibrary(String libName) {
+        synchronized (mPackages) {
+            PackageManagerService.SharedLibraryEntry lib = mSharedLibraries.get(libName);
+            if (lib != null && lib.apk != null) {
+                return mPackages.get(lib.apk);
+            }
+        }
+        return null;
+    }
+
     @Override
     public FeatureInfo[] getSystemAvailableFeatures() {
         Collection<FeatureInfo> featSet;
@@ -4616,8 +4627,7 @@
 
         final ArraySet<PackageParser.Package> pkgs;
         synchronized (mPackages) {
-            pkgs = mDeferredDexOpt;
-            mDeferredDexOpt = null;
+            pkgs = mPackageDexOptimizer.clearDeferredDexOptPackages();
         }
 
         if (pkgs != null) {
@@ -4773,8 +4783,8 @@
         }
         PackageParser.Package p = pkg;
         synchronized (mInstallLock) {
-            performDexOptLI(p, null /* instruction sets */, false /* force dex */,
-                            false /* defer */, true /* include dependencies */);
+            mPackageDexOptimizer.performDexOpt(p, null /* instruction sets */,
+                    false /* force dex */, false /* defer */, true /* include dependencies */);
         }
     }
 
@@ -4823,8 +4833,9 @@
 
         synchronized (mInstallLock) {
             final String[] instructionSets = new String[] { targetInstructionSet };
-            return performDexOptLI(p, instructionSets, false /* force dex */, false /* defer */,
-                    true /* include dependencies */) == DEX_OPT_PERFORMED;
+            int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
+                    false /* forceDex */, false /* defer */, true /* inclDependencies */);
+            return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
         }
     }
 
@@ -4851,226 +4862,6 @@
         mPackageUsage.write(true);
     }
 
-    private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
-             boolean forceDex, boolean defer, ArraySet<String> done) {
-        for (int i=0; i<libs.size(); i++) {
-            PackageParser.Package libPkg;
-            String libName;
-            synchronized (mPackages) {
-                libName = libs.get(i);
-                SharedLibraryEntry lib = mSharedLibraries.get(libName);
-                if (lib != null && lib.apk != null) {
-                    libPkg = mPackages.get(lib.apk);
-                } else {
-                    libPkg = null;
-                }
-            }
-            if (libPkg != null && !done.contains(libName)) {
-                performDexOptLI(libPkg, instructionSets, forceDex, defer, done);
-            }
-        }
-    }
-
-    static final int DEX_OPT_SKIPPED = 0;
-    static final int DEX_OPT_PERFORMED = 1;
-    static final int DEX_OPT_DEFERRED = 2;
-    static final int DEX_OPT_FAILED = -1;
-
-    private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
-            boolean forceDex, boolean defer, ArraySet<String> done) {
-        final String[] instructionSets = targetInstructionSets != null ?
-                targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
-
-        if (done != null) {
-            done.add(pkg.packageName);
-            if (pkg.usesLibraries != null) {
-                performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer, done);
-            }
-            if (pkg.usesOptionalLibraries != null) {
-                performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer, done);
-            }
-        }
-
-        if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) == 0) {
-            return DEX_OPT_SKIPPED;
-        }
-
-        final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
-
-        final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
-        boolean performedDexOpt = false;
-        // There are three basic cases here:
-        // 1.) we need to dexopt, either because we are forced or it is needed
-        // 2.) we are defering a needed dexopt
-        // 3.) we are skipping an unneeded dexopt
-        final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
-        for (String dexCodeInstructionSet : dexCodeInstructionSets) {
-            if (!forceDex && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
-                continue;
-            }
-
-            for (String path : paths) {
-                try {
-                    // This will return DEXOPT_NEEDED if we either cannot find any odex file for this
-                    // patckage or the one we find does not match the image checksum (i.e. it was
-                    // compiled against an old image). It will return PATCHOAT_NEEDED if we can find a
-                    // odex file and it matches the checksum of the image but not its base address,
-                    // meaning we need to move it.
-                    final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
-                            pkg.packageName, dexCodeInstructionSet, defer);
-                    if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
-                        Log.i(TAG, "Running dexopt on: " + path + " pkg="
-                                + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
-                                + " vmSafeMode=" + vmSafeMode);
-                        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
-                        final int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
-                                pkg.packageName, dexCodeInstructionSet, vmSafeMode);
-
-                        if (ret < 0) {
-                            // Don't bother running dexopt again if we failed, it will probably
-                            // just result in an error again. Also, don't bother dexopting for other
-                            // paths & ISAs.
-                            return DEX_OPT_FAILED;
-                        }
-
-                        performedDexOpt = true;
-                    } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
-                        Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
-                        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
-                        final int ret = mInstaller.patchoat(path, sharedGid, !isForwardLocked(pkg),
-                                pkg.packageName, dexCodeInstructionSet);
-
-                        if (ret < 0) {
-                            // Don't bother running patchoat again if we failed, it will probably
-                            // just result in an error again. Also, don't bother dexopting for other
-                            // paths & ISAs.
-                            return DEX_OPT_FAILED;
-                        }
-
-                        performedDexOpt = true;
-                    }
-
-                    // We're deciding to defer a needed dexopt. Don't bother dexopting for other
-                    // paths and instruction sets. We'll deal with them all together when we process
-                    // our list of deferred dexopts.
-                    if (defer && isDexOptNeeded != DexFile.UP_TO_DATE) {
-                        if (mDeferredDexOpt == null) {
-                            mDeferredDexOpt = new ArraySet<PackageParser.Package>();
-                        }
-                        mDeferredDexOpt.add(pkg);
-                        return DEX_OPT_DEFERRED;
-                    }
-                } catch (FileNotFoundException e) {
-                    Slog.w(TAG, "Apk not found for dexopt: " + path);
-                    return DEX_OPT_FAILED;
-                } catch (IOException e) {
-                    Slog.w(TAG, "IOException reading apk: " + path, e);
-                    return DEX_OPT_FAILED;
-                } catch (StaleDexCacheError e) {
-                    Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
-                    return DEX_OPT_FAILED;
-                } catch (Exception e) {
-                    Slog.w(TAG, "Exception when doing dexopt : ", e);
-                    return DEX_OPT_FAILED;
-                }
-            }
-
-            // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
-            // either have either succeeded dexopt, or have had isDexOptNeededInternal tell us
-            // it isn't required. We therefore mark that this package doesn't need dexopt unless
-            // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
-            // it.
-            pkg.mDexOptPerformed.add(dexCodeInstructionSet);
-        }
-
-        // If we've gotten here, we're sure that no error occurred and that we haven't
-        // deferred dex-opt. We've either dex-opted one more paths or instruction sets or
-        // we've skipped all of them because they are up to date. In both cases this
-        // package doesn't need dexopt any longer.
-        return performedDexOpt ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
-    }
-
-    private static String[] getAppDexInstructionSets(ApplicationInfo info) {
-        if (info.primaryCpuAbi != null) {
-            if (info.secondaryCpuAbi != null) {
-                return new String[] {
-                        VMRuntime.getInstructionSet(info.primaryCpuAbi),
-                        VMRuntime.getInstructionSet(info.secondaryCpuAbi) };
-            } else {
-                return new String[] {
-                        VMRuntime.getInstructionSet(info.primaryCpuAbi) };
-            }
-        }
-
-        return new String[] { getPreferredInstructionSet() };
-    }
-
-    private static String[] getAppDexInstructionSets(PackageSetting ps) {
-        if (ps.primaryCpuAbiString != null) {
-            if (ps.secondaryCpuAbiString != null) {
-                return new String[] {
-                        VMRuntime.getInstructionSet(ps.primaryCpuAbiString),
-                        VMRuntime.getInstructionSet(ps.secondaryCpuAbiString) };
-            } else {
-                return new String[] {
-                        VMRuntime.getInstructionSet(ps.primaryCpuAbiString) };
-            }
-        }
-
-        return new String[] { getPreferredInstructionSet() };
-    }
-
-    private static String getPreferredInstructionSet() {
-        if (sPreferredInstructionSet == null) {
-            sPreferredInstructionSet = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
-        }
-
-        return sPreferredInstructionSet;
-    }
-
-    private static List<String> getAllInstructionSets() {
-        final String[] allAbis = Build.SUPPORTED_ABIS;
-        final List<String> allInstructionSets = new ArrayList<String>(allAbis.length);
-
-        for (String abi : allAbis) {
-            final String instructionSet = VMRuntime.getInstructionSet(abi);
-            if (!allInstructionSets.contains(instructionSet)) {
-                allInstructionSets.add(instructionSet);
-            }
-        }
-
-        return allInstructionSets;
-    }
-
-    /**
-     * Returns the instruction set that should be used to compile dex code. In the presence of
-     * a native bridge this might be different than the one shared libraries use.
-     */
-    private static String getDexCodeInstructionSet(String sharedLibraryIsa) {
-        String dexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + sharedLibraryIsa);
-        return (dexCodeIsa.isEmpty() ? sharedLibraryIsa : dexCodeIsa);
-    }
-
-    private static String[] getDexCodeInstructionSets(String[] instructionSets) {
-        ArraySet<String> dexCodeInstructionSets = new ArraySet<String>(instructionSets.length);
-        for (String instructionSet : instructionSets) {
-            dexCodeInstructionSets.add(getDexCodeInstructionSet(instructionSet));
-        }
-        return dexCodeInstructionSets.toArray(new String[dexCodeInstructionSets.size()]);
-    }
-
-    /**
-     * Returns deduplicated list of supported instructions for dex code.
-     */
-    public static String[] getAllDexCodeInstructionSets() {
-        String[] supportedInstructionSets = new String[Build.SUPPORTED_ABIS.length];
-        for (int i = 0; i < supportedInstructionSets.length; i++) {
-            String abi = Build.SUPPORTED_ABIS[i];
-            supportedInstructionSets[i] = VMRuntime.getInstructionSet(abi);
-        }
-        return getDexCodeInstructionSets(supportedInstructionSets);
-    }
-
     @Override
     public void forceDexOpt(String packageName) {
         enforceSystemOrRoot("forceDexOpt");
@@ -5086,25 +4877,14 @@
         synchronized (mInstallLock) {
             final String[] instructionSets = new String[] {
                     getPrimaryInstructionSet(pkg.applicationInfo) };
-            final int res = performDexOptLI(pkg, instructionSets, true, false, true);
-            if (res != DEX_OPT_PERFORMED) {
+            final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets,
+                    true /*forceDex*/, false /* defer */, true /* inclDependencies */);
+            if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
                 throw new IllegalStateException("Failed to dexopt: " + res);
             }
         }
     }
 
-    private int performDexOptLI(PackageParser.Package pkg, String[] instructionSets,
-                                boolean forceDex, boolean defer, boolean inclDependencies) {
-        ArraySet<String> done;
-        if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
-            done = new ArraySet<String>();
-            done.add(pkg.packageName);
-        } else {
-            done = null;
-        }
-        return performDexOptLI(pkg, instructionSets,  forceDex, defer, done);
-    }
-
     private boolean verifyPackageUpdateLPr(PackageSetting oldPkg, PackageParser.Package newPkg) {
         if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
             Slog.w(TAG, "Unable to update from " + oldPkg.name
@@ -5120,10 +4900,6 @@
         return true;
     }
 
-    File getDataPathForUser(int userId) {
-        return new File(mUserAppDataDir.getAbsolutePath() + File.separator + userId);
-    }
-
     private File getDataPathForPackage(String packageName, int userId) {
         /*
          * Until we fully support multiple users, return the directory we
@@ -5791,7 +5567,7 @@
             // pass once we've determined ABI below.
             setNativeLibraryPaths(pkg);
 
-            final boolean isAsec = isForwardLocked(pkg) || isExternal(pkg);
+            final boolean isAsec = pkg.isForwardLocked() || isExternal(pkg);
             final String nativeLibraryRootStr = pkg.applicationInfo.nativeLibraryRootDir;
             final boolean useIsaSpecificSubdirs = pkg.applicationInfo.nativeLibraryRootRequiresIsa;
 
@@ -5967,8 +5743,9 @@
         }
 
         if ((scanFlags & SCAN_NO_DEX) == 0) {
-            if (performDexOptLI(pkg, null /* instruction sets */, forceDex,
-                    (scanFlags & SCAN_DEFER_DEX) != 0, false) == DEX_OPT_FAILED) {
+            int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */,
+                    forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */);
+            if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
                 throw new PackageManagerException(INSTALL_FAILED_DEXOPT, "scanPackageLI");
             }
         }
@@ -6042,8 +5819,10 @@
             if ((scanFlags & SCAN_NO_DEX) == 0) {
                 for (int i = 0; i < clientLibPkgs.size(); i++) {
                     PackageParser.Package clientPkg = clientLibPkgs.get(i);
-                    if (performDexOptLI(clientPkg, null /* instruction sets */, forceDex,
-                            (scanFlags & SCAN_DEFER_DEX) != 0, false) == DEX_OPT_FAILED) {
+                    int result = mPackageDexOptimizer.performDexOpt(clientPkg,
+                            null /* instruction sets */, forceDex,
+                            (scanFlags & SCAN_DEFER_DEX) != 0, false);
+                    if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
                         throw new PackageManagerException(INSTALL_FAILED_DEXOPT,
                                 "scanPackageLI failed to dexopt clientLibPkgs");
                     }
@@ -6512,14 +6291,15 @@
                         ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
                         Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + adjustedAbi);
 
-                        if (performDexOptLI(ps.pkg, null /* instruction sets */, forceDexOpt,
-                                deferDexOpt, true) == DEX_OPT_FAILED) {
+                        int result = mPackageDexOptimizer.performDexOpt(ps.pkg,
+                                null /* instruction sets */, forceDexOpt, deferDexOpt, true);
+                        if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
                             ps.primaryCpuAbiString = null;
                             ps.pkg.applicationInfo.primaryCpuAbi = null;
                             return;
                         } else {
                             mInstaller.rmdex(ps.codePathString,
-                                             getDexCodeInstructionSet(getPreferredInstructionSet()));
+                                    getDexCodeInstructionSet(getPreferredInstructionSet()));
                         }
                     }
                 }
@@ -6592,7 +6372,7 @@
         final String codePath = pkg.codePath;
         final File codeFile = new File(codePath);
         final boolean bundledApp = isSystemApp(info) && !isUpdatedSystemApp(info);
-        final boolean asecApp = isForwardLocked(info) || isExternal(info);
+        final boolean asecApp = info.isForwardLocked() || isExternal(info);
 
         info.nativeLibraryRootDir = null;
         info.nativeLibraryRootRequiresIsa = false;
@@ -9427,6 +9207,25 @@
         }
     }
 
+    private void removeDexFiles(List<String> allCodePaths, String[] instructionSets) {
+        if (!allCodePaths.isEmpty()) {
+            if (instructionSets == null) {
+                throw new IllegalStateException("instructionSet == null");
+            }
+            String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+            for (String codePath : allCodePaths) {
+                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+                    int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
+                    if (retCode < 0) {
+                        Slog.w(TAG, "Couldn't remove dex file for package: "
+                                + " at location " + codePath + ", retcode=" + retCode);
+                        // we don't consider this to be a failure of the core package deletion
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Logic to handle installation of non-ASEC applications, including copying
      * and renaming logic.
@@ -9639,23 +9438,7 @@
             }
 
             cleanUp();
-
-            if (!allCodePaths.isEmpty()) {
-                if (instructionSets == null) {
-                    throw new IllegalStateException("instructionSet == null");
-                }
-                String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
-                for (String codePath : allCodePaths) {
-                    for (String dexCodeInstructionSet : dexCodeInstructionSets) {
-                        int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
-                        if (retCode < 0) {
-                            Slog.w(TAG, "Couldn't remove dex file for package: "
-                                    + " at location " + codePath + ", retcode=" + retCode);
-                            // we don't consider this to be a failure of the core package deletion
-                        }
-                    }
-                }
-            }
+            removeDexFiles(allCodePaths, instructionSets);
         }
 
         boolean doPostDeleteLI(boolean delete) {
@@ -9960,31 +9743,10 @@
 
         private void cleanUpResourcesLI(List<String> allCodePaths) {
             cleanUp();
-
-            if (!allCodePaths.isEmpty()) {
-                if (instructionSets == null) {
-                    throw new IllegalStateException("instructionSet == null");
-                }
-                String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
-                for (String codePath : allCodePaths) {
-                    for (String dexCodeInstructionSet : dexCodeInstructionSets) {
-                        int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
-                        if (retCode < 0) {
-                            Slog.w(TAG, "Couldn't remove dex file for package: "
-                                    + " at location " + codePath + ", retcode=" + retCode);
-                            // we don't consider this to be a failure of the core package deletion
-                        }
-                    }
-                }
-            }
+            removeDexFiles(allCodePaths, instructionSets);
         }
 
-        boolean matchContainer(String app) {
-            if (cid.startsWith(app)) {
-                return true;
-            }
-            return false;
-        }
+
 
         String getPackageName() {
             return getAsecPackageName(cid);
@@ -10302,7 +10064,7 @@
 
             // If deleted package lived in a container, give users a chance to
             // relinquish resources before killing.
-            if (isForwardLocked(deletedPackage) || isExternal(deletedPackage)) {
+            if (deletedPackage.isForwardLocked() || isExternal(deletedPackage)) {
                 if (DEBUG_INSTALL) {
                     Slog.i(TAG, "upgrading pkg " + deletedPackage + " is ASEC-hosted -> UNAVAILABLE");
                 }
@@ -10343,7 +10105,7 @@
                 // Parse old package
                 boolean oldOnSd = isExternal(deletedPackage);
                 int oldParseFlags  = mDefParseFlags | PackageParser.PARSE_CHATTY |
-                        (isForwardLocked(deletedPackage) ? PackageParser.PARSE_FORWARD_LOCK : 0) |
+                        (deletedPackage.isForwardLocked() ? PackageParser.PARSE_FORWARD_LOCK : 0) |
                         (oldOnSd ? PackageParser.PARSE_ON_SDCARD : 0);
                 int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME;
                 try {
@@ -10733,18 +10495,6 @@
         }
     }
 
-    private static boolean isForwardLocked(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
-    }
-
-    private static boolean isForwardLocked(ApplicationInfo info) {
-        return (info.privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
-    }
-
-    private boolean isForwardLocked(PackageSetting ps) {
-        return (ps.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
-    }
-
     private static boolean isMultiArch(PackageSetting ps) {
         return (ps.pkgFlags & ApplicationInfo.FLAG_MULTIARCH) != 0;
     }
@@ -10798,7 +10548,7 @@
         if (isExternal(ps)) {
             installFlags |= PackageManager.INSTALL_EXTERNAL;
         }
-        if (isForwardLocked(ps)) {
+        if (ps.isForwardLocked()) {
             installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
         }
         return installFlags;
@@ -11652,7 +11402,7 @@
             if (ps != null) {
                 libDirRoot = ps.legacyNativeLibraryPathString;
             }
-            if (p != null && (isExternal(p) || isForwardLocked(p))) {
+            if (p != null && (isExternal(p) || p.isForwardLocked())) {
                 String secureContainerId = cidFromCodePath(p.applicationInfo.getBaseCodePath());
                 if (secureContainerId != null) {
                     asecPath = PackageHelper.getSdFilesystem(secureContainerId);
@@ -11666,7 +11416,7 @@
                 Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
                 return false;
             }
-            if (isForwardLocked(p)) {
+            if (p.isForwardLocked()) {
                 publicSrcDir = applicationInfo.getBaseResourcePath();
             }
         }
@@ -13006,7 +12756,7 @@
                     }
 
                     final AsecInstallArgs args = new AsecInstallArgs(cid,
-                            getAppDexInstructionSets(ps), isForwardLocked(ps));
+                            getAppDexInstructionSets(ps), ps.isForwardLocked());
                     // The package status is changed only if the code path
                     // matches between settings and the container id.
                     if (ps.codePathString != null
@@ -13288,7 +13038,7 @@
                             Slog.w(TAG, "No move required. Trying to move to same location");
                             returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
                         } else {
-                            if (isForwardLocked(pkg)) {
+                            if (pkg.isForwardLocked()) {
                                 currInstallFlags |= PackageManager.INSTALL_FORWARD_LOCK;
                                 newInstallFlags |= PackageManager.INSTALL_FORWARD_LOCK;
                             }
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 8ea0bee..06d842a 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -64,4 +64,8 @@
     public boolean isPrivileged() {
         return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
     }
+
+    public boolean isForwardLocked() {
+        return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
+    }
 }
diff --git a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
new file mode 100644
index 0000000..b8a3155
--- /dev/null
+++ b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.policy;
+
+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.content.res.Resources;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
+import android.os.SystemClock;
+import android.view.Display;
+
+import com.android.server.LocalServices;
+
+import java.io.PrintWriter;
+import java.util.concurrent.TimeUnit;
+
+public class BurnInProtectionHelper implements DisplayManager.DisplayListener {
+    private static final String TAG = "BurnInProtection";
+
+    // Default value when max burnin radius is not set.
+    public static final int BURN_IN_RADIUS_MAX_DEFAULT = -1;
+
+    private static final long BURNIN_PROTECTION_WAKEUP_INTERVAL_MS = TimeUnit.MINUTES.toMillis(1);
+    private static final long BURNIN_PROTECTION_MINIMAL_INTERVAL_MS = TimeUnit.SECONDS.toMillis(10);
+
+    private static final String ACTION_BURN_IN_PROTECTION =
+            "android.internal.policy.action.BURN_IN_PROTECTION";
+
+    private static final int BURN_IN_SHIFT_STEP = 2;
+
+    private boolean mBurnInProtectionActive;
+
+    private final int mMinHorizontalBurnInOffset;
+    private final int mMaxHorizontalBurnInOffset;
+    private final int mMinVerticalBurnInOffset;
+    private final int mMaxVerticalBurnInOffset;
+
+    private final int mBurnInRadiusMaxSquared;
+
+    private int mLastBurnInXOffset = 0;
+    /* 1 means increasing, -1 means decreasing */
+    private int mXOffsetDirection = 1;
+    private int mLastBurnInYOffset = 0;
+    /* 1 means increasing, -1 means decreasing */
+    private int mYOffsetDirection = 1;
+
+    private final AlarmManager mAlarmManager;
+    private final PendingIntent mBurnInProtectionIntent;
+    private final DisplayManagerInternal mDisplayManagerInternal;
+    private final Display mDisplay;
+
+    private BroadcastReceiver mBurnInProtectionReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            updateBurnInProtection();
+        }
+    };
+
+    public BurnInProtectionHelper(Context context) {
+        final Resources resources = context.getResources();
+        mMinHorizontalBurnInOffset = resources.getInteger(
+                com.android.internal.R.integer.config_burnInProtectionMinHorizontalOffset);
+        mMaxHorizontalBurnInOffset = resources.getInteger(
+                com.android.internal.R.integer.config_burnInProtectionMaxHorizontalOffset);
+        mMinVerticalBurnInOffset = resources.getInteger(
+                com.android.internal.R.integer.config_burnInProtectionMinVerticalOffset);
+        mMaxVerticalBurnInOffset = resources.getInteger(
+                com.android.internal.R.integer.config_burnInProtectionMaxVerticalOffset);
+        int burnInRadiusMax = resources.getInteger(
+                com.android.internal.R.integer.config_burnInProtectionMaxRadius);
+        if (burnInRadiusMax != BURN_IN_RADIUS_MAX_DEFAULT) {
+            mBurnInRadiusMaxSquared = burnInRadiusMax * burnInRadiusMax;
+        } else {
+            mBurnInRadiusMaxSquared = BURN_IN_RADIUS_MAX_DEFAULT;
+        }
+
+        mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
+        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        context.registerReceiver(mBurnInProtectionReceiver,
+                new IntentFilter(ACTION_BURN_IN_PROTECTION));
+        Intent intent = new Intent(ACTION_BURN_IN_PROTECTION);
+        intent.setPackage(context.getPackageName());
+        intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        mBurnInProtectionIntent = PendingIntent.getBroadcast(context, 0,
+                intent, PendingIntent.FLAG_UPDATE_CURRENT);
+        DisplayManager displayManager =
+                (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
+        mDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+        displayManager.registerDisplayListener(this, null /* handler */);
+    }
+
+    public void startBurnInProtection() {
+        if (!mBurnInProtectionActive) {
+            mBurnInProtectionActive = true;
+            updateBurnInProtection();
+        }
+    }
+
+    private void updateBurnInProtection() {
+        if (mBurnInProtectionActive) {
+            adjustOffsets();
+            mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(),
+                    mLastBurnInXOffset, mLastBurnInYOffset);
+            // Next adjustment at least ten seconds in the future.
+            long next = SystemClock.elapsedRealtime() + BURNIN_PROTECTION_MINIMAL_INTERVAL_MS;
+            // And aligned to the minute.
+            next = next - next % BURNIN_PROTECTION_WAKEUP_INTERVAL_MS
+                    + BURNIN_PROTECTION_WAKEUP_INTERVAL_MS;
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mBurnInProtectionIntent);
+        } else {
+            mAlarmManager.cancel(mBurnInProtectionIntent);
+            mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(), 0, 0);
+        }
+    }
+
+    public void cancelBurnInProtection() {
+        if (mBurnInProtectionActive) {
+            mBurnInProtectionActive = false;
+            updateBurnInProtection();
+        }
+    }
+
+    /**
+     * Gently shifts current burn-in offsets, minimizing the change for the user.
+     *
+     * Shifts are applied in following fashion:
+     * 1) shift horizontally from minimum to the maximum;
+     * 2) shift vertically by one from minimum to the maximum;
+     * 3) shift horizontally from maximum to the minimum;
+     * 4) shift vertically by one from minimum to the maximum.
+     * 5) if you reach the maximum vertically, start shifting back by one from maximum to minimum.
+     *
+     * On top of that, stay within specified radius. If the shift distance from the center is
+     * higher than the radius, skip these values and go the next position that is within the radius.
+     */
+    private void adjustOffsets() {
+        do {
+            // By default, let's just shift the X offset.
+            final int xChange = mXOffsetDirection * BURN_IN_SHIFT_STEP;
+            mLastBurnInXOffset += xChange;
+            if (mLastBurnInXOffset > mMaxHorizontalBurnInOffset
+                    || mLastBurnInXOffset < mMinHorizontalBurnInOffset) {
+                // Whoops, we went too far horizontally. Let's retract..
+                mLastBurnInXOffset -= xChange;
+                // change horizontal direction..
+                mXOffsetDirection *= -1;
+                // and let's shift the Y offset.
+                final int yChange = mYOffsetDirection * BURN_IN_SHIFT_STEP;
+                mLastBurnInYOffset += yChange;
+                if (mLastBurnInYOffset > mMaxVerticalBurnInOffset
+                        || mLastBurnInYOffset < mMinVerticalBurnInOffset) {
+                    // Whoops, we went to far vertically. Let's retract..
+                    mLastBurnInYOffset -= yChange;
+                    // and change vertical direction.
+                    mYOffsetDirection *= -1;
+                }
+            }
+            // If we are outside of the radius, let's try again.
+        } while (mBurnInRadiusMaxSquared != BURN_IN_RADIUS_MAX_DEFAULT
+                && mLastBurnInXOffset * mLastBurnInXOffset + mLastBurnInYOffset * mLastBurnInYOffset
+                        > mBurnInRadiusMaxSquared);
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + TAG);
+        prefix += "  ";
+        pw.println(prefix + "mBurnInProtectionActive=" + mBurnInProtectionActive);
+        pw.println(prefix + "mHorizontalBurnInOffsetsBounds=(" + mMinHorizontalBurnInOffset + ", "
+                + mMaxHorizontalBurnInOffset + ")");
+        pw.println(prefix + "mVerticalBurnInOffsetsBounds=(" + mMinVerticalBurnInOffset + ", "
+                + mMaxVerticalBurnInOffset + ")");
+        pw.println(prefix + "mBurnInRadiusMaxSquared=" + mBurnInRadiusMaxSquared);
+        pw.println(prefix + "mLastBurnInOffset=(" + mLastBurnInXOffset + ", "
+                + mLastBurnInYOffset + ")");
+        pw.println(prefix + "mOfsetChangeDirections=(" + mXOffsetDirection + ", "
+                + mYOffsetDirection + ")");
+    }
+
+    @Override
+    public void onDisplayAdded(int i) {
+    }
+
+    @Override
+    public void onDisplayRemoved(int i) {
+    }
+
+    @Override
+    public void onDisplayChanged(int displayId) {
+        if (displayId == mDisplay.getDisplayId()) {
+            if (mDisplay.getState() == Display.STATE_DOZE
+                    || mDisplay.getState() == Display.STATE_DOZE_SUSPEND) {
+                startBurnInProtection();
+            } else {
+                cancelBurnInProtection();
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f691b4e..c414072 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2006 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -256,6 +257,7 @@
     Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
     SearchManager mSearchManager;
     AccessibilityManager mAccessibilityManager;
+    BurnInProtectionHelper mBurnInProtectionHelper;
 
     // Vibrator pattern for haptic feedback of a long press.
     long[] mLongPressVibePattern;
@@ -1185,6 +1187,10 @@
         mWindowManagerFuncs = windowManagerFuncs;
         mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
         mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
+        if (context.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableBurnInProtection)){
+            mBurnInProtectionHelper = new BurnInProtectionHelper(context);
+        }
 
         mHandler = new PolicyHandler();
         mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
@@ -6457,5 +6463,8 @@
         if (mOrientationListener != null) {
             mOrientationListener.dump(pw, prefix);
         }
+        if (mBurnInProtectionHelper != null) {
+            mBurnInProtectionHelper.dump(prefix, pw);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 111c09b..de9360e 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -18,6 +18,7 @@
 
 import com.android.server.EventLogTags;
 import com.android.server.SystemService;
+import com.android.server.pm.InstructionSets;
 import com.android.server.pm.PackageManagerService;
 
 import android.app.Notification;
@@ -341,7 +342,7 @@
     }
 
     private static boolean isBootImageOnDisk() {
-        for (String instructionSet : PackageManagerService.getAllDexCodeInstructionSets()) {
+        for (String instructionSet : InstructionSets.getAllDexCodeInstructionSets()) {
             if (!VMRuntime.isBootClassPathOnDisk(instructionSet)) {
                 return false;
             }
diff --git a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
index 62f2b48..5e4bd8b 100644
--- a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
+++ b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java
@@ -93,7 +93,9 @@
         }
         c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.SRC);
         mSurfaceControl.setPosition(0, 0);
-        mOverlay.setBounds(0, 0, mScreenSize.x, mScreenSize.y);
+        // Always draw the overlay with square dimensions
+        int size = Math.max(mScreenSize.x, mScreenSize.y);
+        mOverlay.setBounds(0, 0, size, size);
         mOverlay.draw(c);
         mSurface.unlockCanvasAndPost(c);
     }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 3e1c5ff..6d09f55 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -93,10 +93,6 @@
     // stack bounds once the stack is no longer forced to fullscreen.
     final private Rect mPreForceFullscreenBounds;
 
-    // When true this stack is at the top of the screen and should be layed out to extend under
-    // the status bar.
-    boolean mUnderStatusBar;
-
     // Device rotation as of the last time {@link #mBounds} was set.
     int mRotation;
 
@@ -106,7 +102,6 @@
         mOverrideConfig = Configuration.EMPTY;
         mForceFullscreen = false;
         mPreForceFullscreenBounds = new Rect();
-        mUnderStatusBar = true;
         // TODO: remove bounds from log, they are always 0.
         EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId, mBounds.left, mBounds.top,
                 mBounds.right, mBounds.bottom);
@@ -165,7 +160,6 @@
         mDimLayer.setBounds(bounds);
         mAnimationBackgroundSurface.setBounds(bounds);
         mBounds.set(bounds);
-        mUnderStatusBar = (mBounds.top == 0);
         mRotation = rotation;
         updateOverrideConfiguration();
         return true;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index fde0bd5..7e69e87 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4316,8 +4316,13 @@
                         + " ShowWallpaper="
                         + ent.array.getBoolean(
                                 com.android.internal.R.styleable.Window_windowShowWallpaper, false));
-                if (ent.array.getBoolean(
-                        com.android.internal.R.styleable.Window_windowIsTranslucent, false)) {
+                final boolean windowIsTranslucentDefined = ent.array.hasValue(
+                        com.android.internal.R.styleable.Window_windowIsTranslucent);
+                final boolean windowIsTranslucent = ent.array.getBoolean(
+                        com.android.internal.R.styleable.Window_windowIsTranslucent, false);
+                final boolean windowSwipeToDismiss = ent.array.getBoolean(
+                        com.android.internal.R.styleable.Window_windowSwipeToDismiss, false);
+                if (windowIsTranslucent || (!windowIsTranslucentDefined && windowSwipeToDismiss)) {
                     return;
                 }
                 if (ent.array.getBoolean(
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 04aea84..f94ed77 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -16,21 +16,21 @@
 
 package com.android.server.wm;
 
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+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 com.android.server.wm.WindowManagerService.DEBUG_CONFIGURATION;
 import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerService.DEBUG_POWER;
 import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
-import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import android.app.AppOpsManager;
 import android.os.Debug;
@@ -519,9 +519,15 @@
         TaskStack stack = mAppToken != null ? getStack() : null;
         if (stack != null && !stack.isFullscreen()) {
             stack.getBounds(mContainingFrame);
-            if (stack.mUnderStatusBar) {
-                mContainingFrame.top = pf.top;
+            final WindowState imeWin = mService.mInputMethodWindow;
+            if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this
+                    && mContainingFrame.bottom > cf.bottom) {
+                // IME is up and obscuring this window. Adjust the window position so it is visible.
+                mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
             }
+            // Make sure the containing frame is within the content frame so we don't layout
+            // resized window under screen decorations.
+            mContainingFrame.intersect(cf);
             mDisplayFrame.set(mContainingFrame);
         } else {
             mContainingFrame.set(pf);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 770da5b..a19cd9f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -196,13 +196,11 @@
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.ADB_ENABLED);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME_ZONE);
-        GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.BLUETOOTH_ON);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.DATA_ROAMING);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.MODE_RINGER);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.NETWORK_PREFERENCE);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.USB_MASS_STORAGE_ENABLED);
-        GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_ON);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_SLEEP_POLICY);
     }
 
@@ -4053,16 +4051,18 @@
     }
 
     /**
-     * Device owner can only be set on an unprovisioned device, unless it was initiated by "adb", in
-     * which case we allow it if no account is associated with the device.
+     * Device owner can only be set on an unprovisioned device. However, if initiated via "adb",
+     * we also allow it if no accounts or additional users are present on the device.
      */
     private boolean allowedToSetDeviceOwnerOnDevice() {
-        int callingId = Binder.getCallingUid();
-        if (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID) {
-            return AccountManager.get(mContext).getAccounts().length == 0;
-        } else {
-            return !hasUserSetupCompleted(UserHandle.USER_OWNER);
+        if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) {
+            return true;
         }
+
+        int callingId = Binder.getCallingUid();
+        return (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID)
+                && mUserManager.getUserCount() == 1
+                && AccountManager.get(mContext).getAccounts().length == 0;
     }
 
     private void enforceCrossUserPermission(int userHandle) {
@@ -5267,8 +5267,13 @@
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             if (!GLOBAL_SETTINGS_WHITELIST.contains(setting)) {
-                throw new SecurityException(String.format(
-                        "Permission denial: device owners cannot update %1$s", setting));
+                // BLUETOOTH_ON and WIFI_ON used to be supported but not any more. We do not want to
+                // throw a SecurityException not to break apps.
+                if (!Settings.Global.BLUETOOTH_ON.equals(setting)
+                        && !Settings.Global.WIFI_ON.equals(setting)) {
+                    throw new SecurityException(String.format(
+                            "Permission denial: device owners cannot update %1$s", setting));
+                }
             }
 
             long id = Binder.clearCallingIdentity();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index fd990d7..6b8c49c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -385,7 +385,7 @@
         }
 
         @Override
-        public void startSession(IVoiceInteractionService service, Bundle args, int flags) {
+        public void showSession(IVoiceInteractionService service, Bundle args, int flags) {
             synchronized (this) {
                 if (mImpl == null || mImpl.mService == null
                         || service.asBinder() != mImpl.mService.asBinder()) {
@@ -396,7 +396,7 @@
                 final int callingUid = Binder.getCallingUid();
                 final long caller = Binder.clearCallingIdentity();
                 try {
-                    mImpl.startSessionLocked(callingPid, callingUid, args, flags);
+                    mImpl.showSessionLocked(callingPid, callingUid, args, flags);
                 } finally {
                     Binder.restoreCallingIdentity(caller);
                 }
@@ -424,6 +424,42 @@
         }
 
         @Override
+        public boolean showSessionFromSession(IBinder token, Bundle sessionArgs, int flags) {
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "showSessionFromSession without running voice interaction service");
+                    return false;
+                }
+                final int callingPid = Binder.getCallingPid();
+                final int callingUid = Binder.getCallingUid();
+                final long caller = Binder.clearCallingIdentity();
+                try {
+                    return mImpl.showSessionLocked(callingPid, callingUid, sessionArgs, flags);
+                } finally {
+                    Binder.restoreCallingIdentity(caller);
+                }
+            }
+        }
+
+        @Override
+        public boolean hideSessionFromSession(IBinder token) {
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "hideSessionFromSession without running voice interaction service");
+                    return false;
+                }
+                final int callingPid = Binder.getCallingPid();
+                final int callingUid = Binder.getCallingUid();
+                final long caller = Binder.clearCallingIdentity();
+                try {
+                    return mImpl.hideSessionLocked(callingPid, callingUid);
+                } finally {
+                    Binder.restoreCallingIdentity(caller);
+                }
+            }
+        }
+
+        @Override
         public int startVoiceActivity(IBinder token, Intent intent, String resolvedType) {
             synchronized (this) {
                 if (mImpl == null) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index e80f702..9e92867 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -26,7 +26,6 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
-import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -35,20 +34,17 @@
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionService;
 import android.service.voice.IVoiceInteractionSession;
-import android.service.voice.IVoiceInteractionSessionService;
 import android.service.voice.VoiceInteractionService;
 import android.service.voice.VoiceInteractionServiceInfo;
 import android.util.Slog;
 import android.view.IWindowManager;
-import android.view.WindowManager;
 
 import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.os.IResultReceiver;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
-class VoiceInteractionManagerServiceImpl {
+class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback {
     final static String TAG = "VoiceInteractionServiceManager";
 
     final boolean mValid;
@@ -65,7 +61,7 @@
     boolean mBound = false;
     IVoiceInteractionService mService;
 
-    SessionConnection mActiveSession;
+    VoiceInteractionSessionConnection mActiveSession;
 
     final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -101,124 +97,6 @@
         }
     };
 
-    final class SessionConnection implements ServiceConnection {
-        final IBinder mToken = new Binder();
-        final Bundle mArgs;
-        final int mFlags;
-        boolean mBound;
-        IVoiceInteractionSessionService mService;
-        IVoiceInteractionSession mSession;
-        IVoiceInteractor mInteractor;
-        boolean mHaveAssistData;
-        Bundle mAssistData;
-
-        final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
-            @Override
-            public void send(int resultCode, Bundle resultData) throws RemoteException {
-                synchronized (mLock) {
-                    mHaveAssistData = true;
-                    mAssistData = resultData;
-                    if (mSession != null) {
-                        try {
-                            mSession.handleAssist(resultData);
-                        } catch (RemoteException e) {
-                        }
-                    }
-                }
-            }
-        };
-
-        SessionConnection(Bundle args, int flags) {
-            mArgs = args;
-            mFlags = flags;
-            Intent serviceIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
-            serviceIntent.setComponent(mSessionComponentName);
-            mBound = mContext.bindServiceAsUser(serviceIntent, this,
-                    Context.BIND_AUTO_CREATE, new UserHandle(mUser));
-            if (mBound) {
-                try {
-                    mIWindowManager.addWindowToken(mToken,
-                            WindowManager.LayoutParams.TYPE_VOICE_INTERACTION);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failed adding window token", e);
-                }
-                if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) {
-                    try {
-                        mAm.requestAssistContextExtras(0, mAssistReceiver);
-                    } catch (RemoteException e) {
-                    }
-                } else {
-                    mHaveAssistData = true;
-                }
-            } else {
-                Slog.w(TAG, "Failed binding to voice interaction session service " + mComponent);
-            }
-        }
-
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            synchronized (mLock) {
-                mService = IVoiceInteractionSessionService.Stub.asInterface(service);
-                if (mActiveSession == this) {
-                    try {
-                        mService.newSession(mToken, mArgs, mFlags);
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "Failed adding window token", e);
-                    }
-                }
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            mService = null;
-        }
-
-        public void cancel() {
-            if (mBound) {
-                if (mSession != null) {
-                    try {
-                        mSession.destroy();
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "Voice interation session already dead");
-                    }
-                }
-                if (mSession != null) {
-                    try {
-                        mAm.finishVoiceTask(mSession);
-                    } catch (RemoteException e) {
-                    }
-                }
-                mContext.unbindService(this);
-                try {
-                    mIWindowManager.removeWindowToken(mToken);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failed removing window token", e);
-                }
-                mBound = false;
-                mService = null;
-                mSession = null;
-                mInteractor = null;
-            }
-        }
-
-        public void dump(String prefix, PrintWriter pw) {
-            pw.print(prefix); pw.print("mToken="); pw.println(mToken);
-            pw.print(prefix); pw.print("mArgs="); pw.println(mArgs);
-            pw.print(prefix); pw.print("mFlags=0x"); pw.println(Integer.toHexString(mFlags));
-            pw.print(prefix); pw.print("mBound="); pw.println(mBound);
-            if (mBound) {
-                pw.print(prefix); pw.print("mService="); pw.println(mService);
-                pw.print(prefix); pw.print("mSession="); pw.println(mSession);
-                pw.print(prefix); pw.print("mInteractor="); pw.println(mInteractor);
-            }
-            pw.print(prefix); pw.print("mHaveAssistData="); pw.println(mHaveAssistData);
-            if (mHaveAssistData) {
-                pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData);
-            }
-        }
-    };
-
     VoiceInteractionManagerServiceImpl(Context context, Handler handler, Object lock,
             int userHandle, ComponentName service) {
         mContext = context;
@@ -256,12 +134,16 @@
         mContext.registerReceiver(mBroadcastReceiver, filter, null, handler);
     }
 
-    public void startSessionLocked(int callingPid, int callingUid, Bundle args, int flags) {
-        if (mActiveSession != null) {
-            mActiveSession.cancel();
-            mActiveSession = null;
+    public boolean showSessionLocked(int callingPid, int callingUid, Bundle args, int flags) {
+        if (mActiveSession == null) {
+            mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName,
+                    mUser, mContext, this, callingPid, callingUid);
         }
-        mActiveSession = new SessionConnection(args, flags);
+        return mActiveSession.showLocked(args, flags);
+    }
+
+    public boolean hideSessionLocked(int callingPid, int callingUid) {
+        return mActiveSession.hideLocked();
     }
 
     public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
@@ -270,14 +152,7 @@
             Slog.w(TAG, "deliverNewSession does not match active session");
             return false;
         }
-        mActiveSession.mSession = session;
-        mActiveSession.mInteractor = interactor;
-        if (mActiveSession.mHaveAssistData) {
-            try {
-                session.handleAssist(mActiveSession.mAssistData);
-            } catch (RemoteException e) {
-            }
-        }
+        mActiveSession.deliverNewSessionLocked(session, interactor);
         return true;
     }
 
@@ -367,4 +242,11 @@
             Slog.w(TAG, "RemoteException while calling soundModelsChanged", e);
         }
     }
+
+    @Override
+    public void sessionConnectionGone(VoiceInteractionSessionConnection connection) {
+        synchronized (mLock) {
+            finishLocked(connection.mCallingPid, connection.mCallingUid, connection.mToken);
+        }
+    }
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
new file mode 100644
index 0000000..e2b47c3
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.voiceinteraction;
+
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.service.voice.IVoiceInteractionSession;
+import android.service.voice.IVoiceInteractionSessionService;
+import android.service.voice.VoiceInteractionService;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.view.WindowManager;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.os.IResultReceiver;
+
+import java.io.PrintWriter;
+
+final class VoiceInteractionSessionConnection implements ServiceConnection {
+    final static String TAG = "VoiceInteractionServiceManager";
+
+    final IBinder mToken = new Binder();
+    final Object mLock;
+    final ComponentName mSessionComponentName;
+    final Intent mBindIntent;
+    final int mUser;
+    final Context mContext;
+    final Callback mCallback;
+    final int mCallingPid;
+    final int mCallingUid;
+    final IActivityManager mAm;
+    final IWindowManager mIWindowManager;
+    boolean mShown;
+    Bundle mShowArgs;
+    int mShowFlags;
+    boolean mBound;
+    boolean mFullyBound;
+    boolean mCanceled;
+    IVoiceInteractionSessionService mService;
+    IVoiceInteractionSession mSession;
+    IVoiceInteractor mInteractor;
+    boolean mHaveAssistData;
+    Bundle mAssistData;
+
+    public interface Callback {
+        public void sessionConnectionGone(VoiceInteractionSessionConnection connection);
+    }
+
+    final ServiceConnection mFullConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+        }
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+        }
+    };
+
+    final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
+        @Override
+        public void send(int resultCode, Bundle resultData) throws RemoteException {
+            synchronized (mLock) {
+                if (mShown) {
+                    if (mSession != null) {
+                        try {
+                            mSession.handleAssist(resultData);
+                        } catch (RemoteException e) {
+                        }
+                    } else {
+                        mHaveAssistData = true;
+                        mAssistData = resultData;
+                    }
+                }
+            }
+        }
+    };
+
+    public VoiceInteractionSessionConnection(Object lock, ComponentName component, int user,
+            Context context, Callback callback, int callingPid, int callingUid) {
+        mLock = lock;
+        mSessionComponentName = component;
+        mUser = user;
+        mContext = context;
+        mCallback = callback;
+        mCallingPid = callingPid;
+        mCallingUid = callingUid;
+        mAm = ActivityManagerNative.getDefault();
+        mIWindowManager = IWindowManager.Stub.asInterface(
+                ServiceManager.getService(Context.WINDOW_SERVICE));
+        mBindIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
+        mBindIntent.setComponent(mSessionComponentName);
+        mBound = mContext.bindServiceAsUser(mBindIntent, this,
+                Context.BIND_AUTO_CREATE|Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mUser));
+        if (mBound) {
+            try {
+                mIWindowManager.addWindowToken(mToken,
+                        WindowManager.LayoutParams.TYPE_VOICE_INTERACTION);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed adding window token", e);
+            }
+        } else {
+            Slog.w(TAG, "Failed binding to voice interaction session service "
+                    + mSessionComponentName);
+        }
+    }
+
+    public boolean showLocked(Bundle args, int flags) {
+        if (mBound) {
+            if (!mFullyBound) {
+                mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
+                        Context.BIND_AUTO_CREATE|Context.BIND_TREAT_LIKE_ACTIVITY,
+                        new UserHandle(mUser));
+            }
+            mShown = true;
+            mShowArgs = args;
+            mShowFlags = flags;
+            if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) {
+                try {
+                    mAm.requestAssistContextExtras(0, mAssistReceiver);
+                } catch (RemoteException e) {
+                }
+            } else {
+                mHaveAssistData = false;
+                mAssistData = null;
+            }
+            if (mSession != null) {
+                try {
+                    mSession.show(mShowArgs, mShowFlags);
+                    mShowArgs = null;
+                    mShowFlags = 0;
+                } catch (RemoteException e) {
+                }
+                if (mHaveAssistData) {
+                    try {
+                        mSession.handleAssist(mAssistData);
+                        mAssistData = null;
+                        mHaveAssistData = false;
+                    } catch (RemoteException e) {
+                    }
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public boolean hideLocked() {
+        if (mBound) {
+            if (mShown) {
+                mShown = false;
+                mShowArgs = null;
+                mShowFlags = 0;
+                mHaveAssistData = false;
+                mAssistData = null;
+                if (mSession != null) {
+                    try {
+                        mSession.hide();
+                    } catch (RemoteException e) {
+                    }
+                }
+            }
+            if (mFullyBound) {
+                mContext.unbindService(mFullConnection);
+                mFullyBound = false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public boolean deliverNewSessionLocked(IVoiceInteractionSession session,
+            IVoiceInteractor interactor) {
+        mSession = session;
+        mInteractor = interactor;
+        if (mShown) {
+            try {
+                session.show(mShowArgs, mShowFlags);
+                mShowArgs = null;
+                mShowFlags = 0;
+            } catch (RemoteException e) {
+            }
+            if (mHaveAssistData) {
+                try {
+                    session.handleAssist(mAssistData);
+                    mAssistData = null;
+                    mHaveAssistData = false;
+                } catch (RemoteException e) {
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void onServiceConnected(ComponentName name, IBinder service) {
+        synchronized (mLock) {
+            mService = IVoiceInteractionSessionService.Stub.asInterface(service);
+            if (!mCanceled) {
+                try {
+                    mService.newSession(mToken, mShowArgs, mShowFlags);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed adding window token", e);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName name) {
+        mCallback.sessionConnectionGone(this);
+        mService = null;
+    }
+
+    public void cancel() {
+        mCanceled = true;
+        if (mBound) {
+            if (mSession != null) {
+                try {
+                    mSession.destroy();
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Voice interation session already dead");
+                }
+            }
+            if (mSession != null) {
+                try {
+                    mAm.finishVoiceTask(mSession);
+                } catch (RemoteException e) {
+                }
+            }
+            mContext.unbindService(this);
+            try {
+                mIWindowManager.removeWindowToken(mToken);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed removing window token", e);
+            }
+            mBound = false;
+            mService = null;
+            mSession = null;
+            mInteractor = null;
+        }
+        if (mFullyBound) {
+            mContext.unbindService(mFullConnection);
+            mFullyBound = false;
+        }
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("mToken="); pw.println(mToken);
+        pw.print(prefix); pw.print("mShown="); pw.println(mShown);
+        pw.print(prefix); pw.print("mShowArgs="); pw.println(mShowArgs);
+        pw.print(prefix); pw.print("mShowFlags=0x"); pw.println(Integer.toHexString(mShowFlags));
+        pw.print(prefix); pw.print("mBound="); pw.println(mBound);
+        if (mBound) {
+            pw.print(prefix); pw.print("mService="); pw.println(mService);
+            pw.print(prefix); pw.print("mSession="); pw.println(mSession);
+            pw.print(prefix); pw.print("mInteractor="); pw.println(mInteractor);
+        }
+        pw.print(prefix); pw.print("mHaveAssistData="); pw.println(mHaveAssistData);
+        if (mHaveAssistData) {
+            pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData);
+        }
+    }
+};
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 3378872..cfbebba 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -480,6 +480,11 @@
     }
 
     @Override
+    public String getSystemServiceName(Class<?> serviceClass) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public int checkPermission(String permission, int pid, int uid) {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml
index adf572c..36d5d98 100644
--- a/tests/VoiceInteraction/AndroidManifest.xml
+++ b/tests/VoiceInteraction/AndroidManifest.xml
@@ -16,7 +16,8 @@
                 android:label="Test Assist Proxy"
                 android:theme="@android:style/Theme.NoDisplay"
                 android:excludeFromRecents="true"
-                android:noHistory="true">
+                android:noHistory="true"
+                android:taskAffinity="">
             <intent-filter>
                 <action android:name="android.intent.action.ASSIST" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/tests/VoiceInteraction/res/layout/test_interaction.xml b/tests/VoiceInteraction/res/layout/test_interaction.xml
index c4e280e..f4648b57 100644
--- a/tests/VoiceInteraction/res/layout/test_interaction.xml
+++ b/tests/VoiceInteraction/res/layout/test_interaction.xml
@@ -48,4 +48,11 @@
         android:text="@string/abortVoice"
         />
 
+    <Button android:id="@+id/cancel"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:text="@string/cancelVoice"
+    />
+
 </LinearLayout>
diff --git a/tests/VoiceInteraction/res/values/strings.xml b/tests/VoiceInteraction/res/values/strings.xml
index 7eec90c..9f99c97 100644
--- a/tests/VoiceInteraction/res/values/strings.xml
+++ b/tests/VoiceInteraction/res/values/strings.xml
@@ -22,6 +22,7 @@
     <string name="complete">Complete</string>
     <string name="abortVoice">Abort Voice</string>
     <string name="completeVoice">Complete Voice</string>
+    <string name="cancelVoice">Cancel</string>
 
 </resources>
 
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java
index fc04ff5..6a99351 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistProxyActivity.java
@@ -29,6 +29,6 @@
         Intent intent = new Intent(this, MainInteractionService.class);
         intent.setAction(Intent.ACTION_ASSIST);
         intent.putExtras(getIntent());
-        startService(new Intent(this, MainInteractionService.class));
+        startService(intent);
     }
 }
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
index 5d5ae2f..d35bc5c 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -57,6 +57,11 @@
         }
     }
 
+    public void clearAssistData() {
+        mAssistData = null;
+        mTextRects.clear();
+    }
+
     void buildTextRects(AssistData.ViewNode root, int parentLeft, int parentTop) {
         if (root.getVisibility() != View.VISIBLE) {
             return;
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 1aeb98a..1e30aff 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -49,6 +49,7 @@
     static final int STATE_COMMAND = 3;
     static final int STATE_ABORT_VOICE = 4;
     static final int STATE_COMPLETE_VOICE = 5;
+    static final int STATE_DONE=6;
 
     int mState = STATE_IDLE;
     Request mPendingRequest;
@@ -60,12 +61,26 @@
     @Override
     public void onCreate(Bundle args, int startFlags) {
         super.onCreate(args);
-        showWindow();
+    }
+
+    @Override
+    public void onShow(Bundle args, int showFlags) {
+        super.onShow(args, showFlags);
+        mState = STATE_IDLE;
         mStartIntent = args.getParcelable("intent");
         Bundle assist = args.getBundle("assist");
-        if (assist != null) {
-            parseAssistData(assist);
+        parseAssistData(assist);
+        updateState();
+    }
+
+    @Override
+    public void onHide() {
+        super.onHide();
+        if (mAssistVisualizer != null) {
+            mAssistVisualizer.clearAssistData();
         }
+        mState = STATE_DONE;
+        updateState();
     }
 
     @Override
@@ -86,7 +101,6 @@
         mCompleteButton.setOnClickListener(this);
         mAbortButton = (Button)mContentView.findViewById(R.id.abort);
         mAbortButton.setOnClickListener(this);
-        updateState();
         return mContentView;
     }
 
@@ -100,23 +114,35 @@
     }
 
     void parseAssistData(Bundle assistBundle) {
-        Bundle assistContext = assistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
-        if (assistContext != null) {
-            mAssistData = AssistData.getAssistData(assistContext);
-            mAssistData.dump();
-            if (mAssistVisualizer != null) {
-                mAssistVisualizer.setAssistData(mAssistData);
+        if (assistBundle != null) {
+            Bundle assistContext = assistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
+            if (assistContext != null) {
+                mAssistData = AssistData.getAssistData(assistContext);
+                mAssistData.dump();
+                if (mAssistVisualizer != null) {
+                    mAssistVisualizer.setAssistData(mAssistData);
+                }
+                return;
             }
         }
+        if (mAssistVisualizer != null) {
+            mAssistVisualizer.clearAssistData();
+        }
     }
 
     void updateState() {
         if (mState == STATE_IDLE) {
             mTopContent.setVisibility(View.VISIBLE);
             mBottomContent.setVisibility(View.GONE);
+            mAssistVisualizer.setVisibility(View.VISIBLE);
+        } else if (mState == STATE_DONE) {
+            mTopContent.setVisibility(View.GONE);
+            mBottomContent.setVisibility(View.GONE);
+            mAssistVisualizer.setVisibility(View.GONE);
         } else {
             mTopContent.setVisibility(View.GONE);
             mBottomContent.setVisibility(View.VISIBLE);
+            mAssistVisualizer.setVisibility(View.GONE);
         }
         mStartButton.setEnabled(mState == STATE_IDLE);
         mConfirmButton.setEnabled(mState == STATE_CONFIRM || mState == STATE_COMMAND);
@@ -136,18 +162,12 @@
                 mPendingRequest.sendCommandResult(true, null);
             }
             mPendingRequest = null;
-            mState = STATE_IDLE;
-            updateState();
         } else if (v == mAbortButton) {
             mPendingRequest.sendAbortVoiceResult(null);
             mPendingRequest = null;
-            mState = STATE_IDLE;
-            updateState();
         } else if (v== mCompleteButton) {
             mPendingRequest.sendCompleteVoiceResult(null);
             mPendingRequest = null;
-            mState = STATE_IDLE;
-            updateState();
         }
     }
 
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
index 8522cdc..023e0ec 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
@@ -31,8 +31,10 @@
     static final String TAG = "TestInteractionActivity";
 
     VoiceInteractor mInteractor;
+    VoiceInteractor.Request mCurrentRequest = null;
     Button mAbortButton;
     Button mCompleteButton;
+    Button mCancelButton;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -56,9 +58,11 @@
         mAbortButton.setOnClickListener(this);
         mCompleteButton = (Button)findViewById(R.id.complete);
         mCompleteButton.setOnClickListener(this);
+        mCancelButton = (Button)findViewById(R.id.cancel);
+        mCancelButton.setOnClickListener(this);
 
         mInteractor = getVoiceInteractor();
-        VoiceInteractor.ConfirmationRequest req = new VoiceInteractor.ConfirmationRequest(
+        mCurrentRequest = new VoiceInteractor.ConfirmationRequest(
                 "This is a confirmation", null) {
             @Override
             public void onCancel() {
@@ -72,7 +76,7 @@
                 getActivity().finish();
             }
         };
-        mInteractor.submitRequest(req);
+        mInteractor.submitRequest(mCurrentRequest);
     }
 
     @Override
@@ -112,6 +116,9 @@
                 }
             };
             mInteractor.submitRequest(req);
+        } else if (v == mCancelButton && mCurrentRequest != null) {
+            Log.i(TAG, "Cancel request");
+            mCurrentRequest.cancel();
         }
     }
 
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 8af4f50..5c6d870 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -132,10 +132,14 @@
 
         if "extends" in raw:
             self.extends = raw[raw.index("extends")+1]
+            self.extends_path = self.extends.split(".")
         else:
             self.extends = None
+            self.extends_path = []
 
         self.fullname = self.pkg.name + "." + self.fullname
+        self.fullname_path = self.fullname.split(".")
+
         self.name = self.fullname[self.fullname.rindex(".")+1:]
 
     def __repr__(self):
@@ -150,6 +154,7 @@
 
         raw = raw.split()
         self.name = raw[raw.index("package")+1]
+        self.name_path = self.name.split(".")
 
     def __repr__(self):
         return self.raw
@@ -760,7 +765,7 @@
     if not clazz.name.endswith("Manager"): return
 
     for c in clazz.ctors:
-        error(clazz, c, None, "Managers must always be obtained from Context")
+        error(clazz, c, None, "Managers must always be obtained from Context; no direct constructors")
 
 
 def verify_boxed(clazz):
@@ -846,35 +851,26 @@
     """Verifies that methods adding listener/callback have overload
     for specifying delivery thread."""
 
-    # Ignore UI components which deliver things on main thread
+    # Ignore UI packages which assume main thread
     skip = [
-        "android.animation",
-        "android.view",
-        "android.graphics",
-        "android.transition",
-        "android.widget",
-        "android.webkit",
+        "animation",
+        "view",
+        "graphics",
+        "transition",
+        "widget",
+        "webkit",
     ]
     for s in skip:
-        if clazz.fullname.startswith(s): return
-        if clazz.extends and clazz.extends.startswith(s): return
+        if s in clazz.pkg.name_path: return
+        if s in clazz.extends_path: return
 
-    skip = [
-        "android.app.ActionBar",
-        "android.app.AlertDialog",
-        "android.app.AlertDialog.Builder",
-        "android.app.Application",
-        "android.app.Activity",
-        "android.app.Dialog",
-        "android.app.Fragment",
-        "android.app.FragmentManager",
-        "android.app.LoaderManager",
-        "android.app.ListActivity",
-        "android.app.AlertDialog.Builder"
-        "android.content.Loader",
-    ]
-    for s in skip:
-        if clazz.fullname == s or clazz.extends == s: return
+    # Ignore UI classes which assume main thread
+    if "app" in clazz.pkg.name_path or "app" in clazz.extends_path:
+        for s in ["ActionBar","Dialog","Application","Activity","Fragment","Loader"]:
+            if s in clazz.fullname: return
+    if "content" in clazz.pkg.name_path or "content" in clazz.extends_path:
+        for s in ["Loader"]:
+            if s in clazz.fullname: return
 
     found = {}
     by_name = collections.defaultdict(list)
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 2f62b93..d88a867 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
@@ -17,6 +17,7 @@
 package com.android.layoutlib.bridge.android;
 
 import android.os.IBinder;
+
 import com.android.annotations.Nullable;
 import com.android.ide.common.rendering.api.AssetRepository;
 import com.android.ide.common.rendering.api.ILayoutPullParser;
@@ -73,6 +74,7 @@
 import android.view.BridgeInflater;
 import android.view.Display;
 import android.view.DisplayAdjustments;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
@@ -495,6 +497,34 @@
         throw new UnsupportedOperationException("Unsupported Service: " + service);
     }
 
+    @Override
+    public String getSystemServiceName(Class<?> serviceClass) {
+        if (serviceClass.equals(LayoutInflater.class)) {
+            return LAYOUT_INFLATER_SERVICE;
+        }
+
+        if (serviceClass.equals(TextServicesManager.class)) {
+            return TEXT_SERVICES_MANAGER_SERVICE;
+        }
+
+        if (serviceClass.equals(WindowManager.class)) {
+            return WINDOW_SERVICE;
+        }
+
+        if (serviceClass.equals(PowerManager.class)) {
+            return POWER_SERVICE;
+        }
+
+        if (serviceClass.equals(DisplayManager.class)) {
+            return DISPLAY_SERVICE;
+        }
+
+        if (serviceClass.equals(AccessibilityManager.class)) {
+            return ACCESSIBILITY_SERVICE;
+        }
+
+        throw new UnsupportedOperationException("Unsupported Service: " + serviceClass);
+    }
 
     @Override
     public final BridgeTypedArray obtainStyledAttributes(int[] attrs) {