Merge "Remove Roboto fonts and their build rules"
diff --git a/api/current.txt b/api/current.txt
index 6749453..e92e9f4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -664,6 +664,8 @@
     field public static final int host = 16842792; // 0x1010028
     field public static final int icon = 16842754; // 0x1010002
     field public static final int iconPreview = 16843337; // 0x1010249
+    field public static final int iconTint = 16844000; // 0x10104e0
+    field public static final int iconTintMode = 16844001; // 0x10104e1
     field public static final int iconifiedByDefault = 16843514; // 0x10102fa
     field public static final int id = 16842960; // 0x10100d0
     field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -873,6 +875,8 @@
     field public static final int navigationContentDescription = 16843969; // 0x10104c1
     field public static final int navigationIcon = 16843968; // 0x10104c0
     field public static final int navigationMode = 16843471; // 0x10102cf
+    field public static final int navigationTint = 16844004; // 0x10104e4
+    field public static final int navigationTintMode = 16844005; // 0x10104e5
     field public static final int negativeButtonText = 16843254; // 0x10101f6
     field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
     field public static final int nextFocusDown = 16842980; // 0x10100e4
@@ -904,6 +908,8 @@
     field public static final int overScrollFooter = 16843459; // 0x10102c3
     field public static final int overScrollHeader = 16843458; // 0x10102c2
     field public static final int overScrollMode = 16843457; // 0x10102c1
+    field public static final int overflowTint = 16844002; // 0x10104e2
+    field public static final int overflowTintMode = 16844003; // 0x10104e3
     field public static final int overlapAnchor = 16843874; // 0x1010462
     field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
     field public static final int packageNames = 16843649; // 0x1010381
@@ -1710,10 +1716,10 @@
     field public static final int message = 16908299; // 0x102000b
     field public static final int navigationBarBackground = 16908336; // 0x1020030
     field public static final int paste = 16908322; // 0x1020022
-    field public static final int pasteAsPlainText = 16908339; // 0x1020033
+    field public static final int pasteAsPlainText = 16908337; // 0x1020031
     field public static final int primary = 16908300; // 0x102000c
     field public static final int progress = 16908301; // 0x102000d
-    field public static final int redo = 16908338; // 0x1020032
+    field public static final int redo = 16908339; // 0x1020033
     field public static final int secondaryProgress = 16908303; // 0x102000f
     field public static final int selectAll = 16908319; // 0x102001f
     field public static final int selectTextMode = 16908333; // 0x102002d
@@ -1730,7 +1736,7 @@
     field public static final int text2 = 16908309; // 0x1020015
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
-    field public static final int undo = 16908337; // 0x1020031
+    field public static final int undo = 16908338; // 0x1020032
     field public static final int widget_frame = 16908312; // 0x1020018
   }
 
@@ -2019,6 +2025,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 +3753,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 +3773,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 +3792,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);
@@ -7319,6 +7326,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();
@@ -7448,7 +7456,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;
@@ -7491,20 +7499,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);
@@ -7513,13 +7522,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);
@@ -21779,7 +21788,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
@@ -25048,9 +25056,12 @@
     ctor public ContactsContract.QuickContact();
     method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, int, java.lang.String[]);
     method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, int, java.lang.String[]);
+    method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, java.lang.String[], java.lang.String);
+    method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, java.lang.String[], java.lang.String);
     field public static final java.lang.String ACTION_QUICK_CONTACT = "android.provider.action.QUICK_CONTACT";
     field public static final java.lang.String EXTRA_EXCLUDE_MIMES = "android.provider.extra.EXCLUDE_MIMES";
     field public static final java.lang.String EXTRA_MODE = "android.provider.extra.MODE";
+    field public static final java.lang.String EXTRA_PRIORITIZED_MIMETYPE = "android.provider.extra.PRIORITIZED_MIMETYPE";
     field public static final int MODE_LARGE = 3; // 0x3
     field public static final int MODE_MEDIUM = 2; // 0x2
     field public static final int MODE_SMALL = 1; // 0x1
@@ -27655,7 +27666,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
@@ -27667,6 +27678,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();
@@ -27681,14 +27693,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);
   }
@@ -28507,6 +28522,15 @@
     field public static final int STDERR_FILENO;
     field public static final int STDIN_FILENO;
     field public static final int STDOUT_FILENO;
+    field public static final int ST_MANDLOCK;
+    field public static final int ST_NOATIME;
+    field public static final int ST_NODEV;
+    field public static final int ST_NODIRATIME;
+    field public static final int ST_NOEXEC;
+    field public static final int ST_NOSUID;
+    field public static final int ST_RDONLY;
+    field public static final int ST_RELATIME;
+    field public static final int ST_SYNCHRONOUS;
     field public static final int S_IFBLK;
     field public static final int S_IFCHR;
     field public static final int S_IFDIR;
@@ -28746,6 +28770,7 @@
     method public boolean handleMmi(java.lang.String);
     method public boolean isInCall();
     method public void showInCallScreen(boolean);
+    field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
@@ -29842,6 +29867,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();
@@ -33479,6 +33505,8 @@
     method public abstract android.view.MenuItem setEnabled(boolean);
     method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
     method public abstract android.view.MenuItem setIcon(int);
+    method public abstract android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
+    method public abstract android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
     method public abstract android.view.MenuItem setIntent(android.content.Intent);
     method public abstract android.view.MenuItem setNumericShortcut(char);
     method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener);
@@ -37418,6 +37446,8 @@
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onDetachedFromWindow();
     method public void setOnMenuItemClickListener(android.widget.ActionMenuView.OnMenuItemClickListener);
+    method public void setOverflowTintList(android.content.res.ColorStateList);
+    method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
     method public void setPopupTheme(int);
     method public boolean showOverflowMenu();
   }
@@ -38746,6 +38776,7 @@
     method public void setImageToDefault();
     method public void setMode(int);
     method public void setOverlay(android.graphics.drawable.Drawable);
+    method public void setPrioritizedMimeType(java.lang.String);
     field protected java.lang.String[] mExcludeMimes;
   }
 
@@ -38843,6 +38874,7 @@
     method public void addRule(int);
     method public void addRule(int, int);
     method public java.lang.String debug(java.lang.String);
+    method public int getRule(int);
     method public int[] getRules();
     method public void removeRule(int);
     field public boolean alignWithParent;
@@ -39712,7 +39744,11 @@
     method public void setNavigationIcon(int);
     method public void setNavigationIcon(android.graphics.drawable.Drawable);
     method public void setNavigationOnClickListener(android.view.View.OnClickListener);
+    method public void setNavigationTintList(android.content.res.ColorStateList);
+    method public void setNavigationTintMode(android.graphics.PorterDuff.Mode);
     method public void setOnMenuItemClickListener(android.widget.Toolbar.OnMenuItemClickListener);
+    method public void setOverflowTintList(android.content.res.ColorStateList);
+    method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
     method public void setPopupTheme(int);
     method public void setSubtitle(int);
     method public void setSubtitle(java.lang.CharSequence);
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 b2e44a3..29ebf57 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -736,6 +736,8 @@
     field public static final int host = 16842792; // 0x1010028
     field public static final int icon = 16842754; // 0x1010002
     field public static final int iconPreview = 16843337; // 0x1010249
+    field public static final int iconTint = 16844000; // 0x10104e0
+    field public static final int iconTintMode = 16844001; // 0x10104e1
     field public static final int iconifiedByDefault = 16843514; // 0x10102fa
     field public static final int id = 16842960; // 0x10100d0
     field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -945,6 +947,8 @@
     field public static final int navigationContentDescription = 16843969; // 0x10104c1
     field public static final int navigationIcon = 16843968; // 0x10104c0
     field public static final int navigationMode = 16843471; // 0x10102cf
+    field public static final int navigationTint = 16844004; // 0x10104e4
+    field public static final int navigationTintMode = 16844005; // 0x10104e5
     field public static final int negativeButtonText = 16843254; // 0x10101f6
     field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
     field public static final int nextFocusDown = 16842980; // 0x10100e4
@@ -976,6 +980,8 @@
     field public static final int overScrollFooter = 16843459; // 0x10102c3
     field public static final int overScrollHeader = 16843458; // 0x10102c2
     field public static final int overScrollMode = 16843457; // 0x10102c1
+    field public static final int overflowTint = 16844002; // 0x10104e2
+    field public static final int overflowTintMode = 16844003; // 0x10104e3
     field public static final int overlapAnchor = 16843874; // 0x1010462
     field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
     field public static final int packageNames = 16843649; // 0x1010381
@@ -1786,10 +1792,10 @@
     field public static final int message = 16908299; // 0x102000b
     field public static final int navigationBarBackground = 16908336; // 0x1020030
     field public static final int paste = 16908322; // 0x1020022
-    field public static final int pasteAsPlainText = 16908339; // 0x1020033
+    field public static final int pasteAsPlainText = 16908337; // 0x1020031
     field public static final int primary = 16908300; // 0x102000c
     field public static final int progress = 16908301; // 0x102000d
-    field public static final int redo = 16908338; // 0x1020032
+    field public static final int redo = 16908339; // 0x1020033
     field public static final int secondaryProgress = 16908303; // 0x102000f
     field public static final int selectAll = 16908319; // 0x102001f
     field public static final int selectTextMode = 16908333; // 0x102002d
@@ -1806,7 +1812,7 @@
     field public static final int text2 = 16908309; // 0x1020015
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
-    field public static final int undo = 16908337; // 0x1020031
+    field public static final int undo = 16908338; // 0x1020032
     field public static final int widget_frame = 16908312; // 0x1020018
   }
 
@@ -2097,6 +2103,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 +3842,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 +3862,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 +3881,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);
@@ -7524,6 +7531,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();
@@ -7659,7 +7667,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;
@@ -7702,20 +7710,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);
@@ -7724,13 +7733,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);
@@ -23368,7 +23377,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
@@ -26647,9 +26655,12 @@
     ctor public ContactsContract.QuickContact();
     method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, int, java.lang.String[]);
     method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, int, java.lang.String[]);
+    method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, java.lang.String[], java.lang.String);
+    method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, java.lang.String[], java.lang.String);
     field public static final java.lang.String ACTION_QUICK_CONTACT = "android.provider.action.QUICK_CONTACT";
     field public static final java.lang.String EXTRA_EXCLUDE_MIMES = "android.provider.extra.EXCLUDE_MIMES";
     field public static final java.lang.String EXTRA_MODE = "android.provider.extra.MODE";
+    field public static final java.lang.String EXTRA_PRIORITIZED_MIMETYPE = "android.provider.extra.PRIORITIZED_MIMETYPE";
     field public static final int MODE_LARGE = 3; // 0x3
     field public static final int MODE_MEDIUM = 2; // 0x2
     field public static final int MODE_SMALL = 1; // 0x1
@@ -29344,7 +29355,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
@@ -29356,6 +29367,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();
@@ -29370,14 +29382,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);
   }
@@ -30196,6 +30211,15 @@
     field public static final int STDERR_FILENO;
     field public static final int STDIN_FILENO;
     field public static final int STDOUT_FILENO;
+    field public static final int ST_MANDLOCK;
+    field public static final int ST_NOATIME;
+    field public static final int ST_NODEV;
+    field public static final int ST_NODIRATIME;
+    field public static final int ST_NOEXEC;
+    field public static final int ST_NOSUID;
+    field public static final int ST_RDONLY;
+    field public static final int ST_RELATIME;
+    field public static final int ST_SYNCHRONOUS;
     field public static final int S_IFBLK;
     field public static final int S_IFCHR;
     field public static final int S_IFDIR;
@@ -30866,6 +30890,7 @@
     method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
     field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
     field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
+    field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
@@ -32003,6 +32028,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();
@@ -35640,6 +35666,8 @@
     method public abstract android.view.MenuItem setEnabled(boolean);
     method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
     method public abstract android.view.MenuItem setIcon(int);
+    method public abstract android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
+    method public abstract android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
     method public abstract android.view.MenuItem setIntent(android.content.Intent);
     method public abstract android.view.MenuItem setNumericShortcut(char);
     method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener);
@@ -39877,6 +39905,8 @@
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onDetachedFromWindow();
     method public void setOnMenuItemClickListener(android.widget.ActionMenuView.OnMenuItemClickListener);
+    method public void setOverflowTintList(android.content.res.ColorStateList);
+    method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
     method public void setPopupTheme(int);
     method public boolean showOverflowMenu();
   }
@@ -41205,6 +41235,7 @@
     method public void setImageToDefault();
     method public void setMode(int);
     method public void setOverlay(android.graphics.drawable.Drawable);
+    method public void setPrioritizedMimeType(java.lang.String);
     field protected java.lang.String[] mExcludeMimes;
   }
 
@@ -41302,6 +41333,7 @@
     method public void addRule(int);
     method public void addRule(int, int);
     method public java.lang.String debug(java.lang.String);
+    method public int getRule(int);
     method public int[] getRules();
     method public void removeRule(int);
     field public boolean alignWithParent;
@@ -42171,7 +42203,11 @@
     method public void setNavigationIcon(int);
     method public void setNavigationIcon(android.graphics.drawable.Drawable);
     method public void setNavigationOnClickListener(android.view.View.OnClickListener);
+    method public void setNavigationTintList(android.content.res.ColorStateList);
+    method public void setNavigationTintMode(android.graphics.PorterDuff.Mode);
     method public void setOnMenuItemClickListener(android.widget.Toolbar.OnMenuItemClickListener);
+    method public void setOverflowTintList(android.content.res.ColorStateList);
+    method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
     method public void setPopupTheme(int);
     method public void setSubtitle(int);
     method public void setSubtitle(java.lang.CharSequence);
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/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index 3a2c21b..a3b3022 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -31,20 +31,21 @@
 import com.android.internal.R;
 
 /**
- * A dialog that prompts the user for the time of day using a {@link TimePicker}.
+ * A dialog that prompts the user for the time of day using a
+ * {@link TimePicker}.
  *
- * <p>See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
- * guide.</p>
+ * <p>
+ * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
+ * guide.
  */
 public class TimePickerDialog extends AlertDialog implements OnClickListener,
         OnTimeChangedListener {
-
     private static final String HOUR = "hour";
     private static final String MINUTE = "minute";
     private static final String IS_24_HOUR = "is24hour";
 
     private final TimePicker mTimePicker;
-    private final OnTimeSetListener mTimeSetCallback;
+    private final OnTimeSetListener mTimeSetListener;
 
     private final int mInitialHourOfDay;
     private final int mInitialMinute;
@@ -52,59 +53,70 @@
 
     /**
      * The callback interface used to indicate the user is done filling in
-     * the time (they clicked on the 'Done' button).
+     * the time (e.g. they clicked on the 'OK' button).
      */
     public interface OnTimeSetListener {
-
         /**
-         * @param view The view associated with this listener.
-         * @param hourOfDay The hour that was set.
-         * @param minute The minute that was set.
+         * Called when the user is done setting a new time and the dialog has
+         * closed.
+         *
+         * @param view the view associated with this listener
+         * @param hourOfDay the hour that was set
+         * @param minute the minute that was set
          */
-        void onTimeSet(TimePicker view, int hourOfDay, int minute);
+        public void onTimeSet(TimePicker view, int hourOfDay, int minute);
     }
 
     /**
-     * @param context Parent.
-     * @param callBack How parent is notified.
-     * @param hourOfDay The initial hour.
-     * @param minute The initial minute.
-     * @param is24HourView Whether this is a 24 hour view, or AM/PM.
+     * Creates a new time picker dialog.
+     *
+     * @param context the parent context
+     * @param listener the listener to call when the time is set
+     * @param hourOfDay the initial hour
+     * @param minute the initial minute
+     * @param is24HourView whether this is a 24 hour view or AM/PM
      */
-    public TimePickerDialog(Context context,
-            OnTimeSetListener callBack,
-            int hourOfDay, int minute, boolean is24HourView) {
-        this(context, 0, callBack, hourOfDay, minute, is24HourView);
+    public TimePickerDialog(Context context, OnTimeSetListener listener, int hourOfDay, int minute,
+            boolean is24HourView) {
+        this(context, 0, listener, hourOfDay, minute, is24HourView);
     }
 
-    static int resolveDialogTheme(Context context, int resid) {
-        if (resid == 0) {
+    static int resolveDialogTheme(Context context, int resId) {
+        if (resId == 0) {
             final TypedValue outValue = new TypedValue();
             context.getTheme().resolveAttribute(R.attr.timePickerDialogTheme, outValue, true);
             return outValue.resourceId;
         } else {
-            return resid;
+            return resId;
         }
     }
 
     /**
-     * @param context Parent.
-     * @param theme the theme to apply to this dialog
-     * @param callBack How parent is notified.
-     * @param hourOfDay The initial hour.
-     * @param minute The initial minute.
+     * Creates a new time picker dialog with the specified theme.
+     *
+     * @param context the parent context
+     * @param themeResId the resource ID of the theme to apply to this dialog
+     * @param listener the listener to call when the time is set
+     * @param hourOfDay the initial hour
+     * @param minute the initial minute
      * @param is24HourView Whether this is a 24 hour view, or AM/PM.
      */
-    public TimePickerDialog(Context context, int theme, OnTimeSetListener callBack, int hourOfDay,
-            int minute, boolean is24HourView) {
-        super(context, resolveDialogTheme(context, theme));
+    public TimePickerDialog(Context context, int themeResId, OnTimeSetListener listener,
+            int hourOfDay, int minute, boolean is24HourView) {
+        super(context, resolveDialogTheme(context, themeResId));
 
-        mTimeSetCallback = callBack;
+        mTimeSetListener = listener;
         mInitialHourOfDay = hourOfDay;
         mInitialMinute = minute;
         mIs24HourView = is24HourView;
 
         final Context themeContext = getContext();
+
+
+        final TypedValue outValue = new TypedValue();
+        context.getTheme().resolveAttribute(R.attr.timePickerDialogTheme, outValue, true);
+        final int layoutResId = outValue.resourceId;
+
         final LayoutInflater inflater = LayoutInflater.from(themeContext);
         final View view = inflater.inflate(R.layout.time_picker_dialog, null);
         setView(view);
@@ -129,8 +141,8 @@
     public void onClick(DialogInterface dialog, int which) {
         switch (which) {
             case BUTTON_POSITIVE:
-                if (mTimeSetCallback != null) {
-                    mTimeSetCallback.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
+                if (mTimeSetListener != null) {
+                    mTimeSetListener.onTimeSet(mTimePicker, mTimePicker.getCurrentHour(),
                             mTimePicker.getCurrentMinute());
                 }
                 break;
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/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c5b6320..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.
@@ -3307,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)
@@ -3362,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/UndoManager.java b/core/java/android/content/UndoManager.java
index e3bc238..559b01c 100644
--- a/core/java/android/content/UndoManager.java
+++ b/core/java/android/content/UndoManager.java
@@ -105,8 +105,7 @@
             return owner;
         }
 
-        owner = new UndoOwner(tag);
-        owner.mManager = this;
+        owner = new UndoOwner(tag, this);
         owner.mData = data;
         mOwners.put(tag, owner);
         return owner;
@@ -116,7 +115,6 @@
         // XXX need to figure out how to prune.
         if (false) {
             mOwners.remove(owner.mTag);
-            owner.mManager = null;
         }
     }
 
@@ -202,7 +200,7 @@
         UndoOwner owner = mStateOwners[idx];
         if (owner == null) {
             String tag = in.readString();
-            owner = new UndoOwner(tag);
+            owner = new UndoOwner(tag, this);
             mStateOwners[idx] = owner;
             mOwners.put(tag, owner);
         }
diff --git a/core/java/android/content/UndoOwner.java b/core/java/android/content/UndoOwner.java
index d0cdc95..9106588 100644
--- a/core/java/android/content/UndoOwner.java
+++ b/core/java/android/content/UndoOwner.java
@@ -23,8 +23,8 @@
  */
 public class UndoOwner {
     final String mTag;
+    final UndoManager mManager;
 
-    UndoManager mManager;
     Object mData;
     int mOpCount;
 
@@ -32,8 +32,15 @@
     int mStateSeq;
     int mSavedIdx;
 
-    UndoOwner(String tag) {
+    UndoOwner(String tag, UndoManager manager) {
+        if (tag == null) {
+            throw new NullPointerException("tag can't be null");
+        }
+        if (manager == null) {
+            throw new NullPointerException("manager can't be null");
+        }
         mTag = tag;
+        mManager = manager;
     }
 
     /**
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/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index b42d8bc..ace402a 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -462,46 +462,6 @@
         return mColors;
     }
 
-    /**
-     * If the color state list does not already have an entry matching the
-     * specified state, prepends a state set and color pair to a color state
-     * list.
-     * <p>
-     * This is a workaround used in TimePicker and DatePicker until we can
-     * add support for theme attributes in ColorStateList.
-     *
-     * @param colorStateList the source color state list
-     * @param state the state to prepend
-     * @param color the color to use for the given state
-     * @return a new color state list, or the source color state list if there
-     *         was already a matching state set
-     *
-     * @hide Remove when we can support theme attributes.
-     */
-    public static ColorStateList addFirstIfMissing(
-            ColorStateList colorStateList, int state, int color) {
-        final int[][] inputStates = colorStateList.getStates();
-        for (int i = 0; i < inputStates.length; i++) {
-            final int[] inputState = inputStates[i];
-            for (int j = 0; j < inputState.length; j++) {
-                if (inputState[j] == state) {
-                    return colorStateList;
-                }
-            }
-        }
-
-        final int[][] outputStates = new int[inputStates.length + 1][];
-        System.arraycopy(inputStates, 0, outputStates, 1, inputStates.length);
-        outputStates[0] = new int[] { state };
-
-        final int[] inputColors = colorStateList.getColors();
-        final int[] outputColors = new int[inputColors.length + 1];
-        System.arraycopy(inputColors, 0, outputColors, 1, inputColors.length);
-        outputColors[0] = color;
-
-        return new ColorStateList(outputStates, outputColors);
-    }
-
     @Override
     public String toString() {
         return "ColorStateList{" +
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/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 67ac043..9cc12b5 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -8069,6 +8069,14 @@
         public static final String EXTRA_MODE = "android.provider.extra.MODE";
 
         /**
+         * Extra used to specify which mimetype should be prioritized in the QuickContacts UI.
+         * For example, passing the value {@link CommonDataKinds.Phone#CONTENT_ITEM_TYPE} can
+         * cause phone numbers to be displayed more prominently in QuickContacts.
+         */
+        public static final String EXTRA_PRIORITIZED_MIMETYPE
+                = "android.provider.extra.PRIORITIZED_MIMETYPE";
+
+        /**
          * Extra used to indicate a list of specific MIME-types to exclude and not display in the
          * QuickContacts dialog. Stored as a {@link String} array.
          */
@@ -8206,6 +8214,80 @@
             startActivityWithErrorToast(context, intent);
         }
 
+        /**
+         * Trigger a dialog that lists the various methods of interacting with
+         * the requested {@link Contacts} entry. This may be based on available
+         * {@link ContactsContract.Data} rows under that contact, and may also
+         * include social status and presence details.
+         *
+         * @param context The parent {@link Context} that may be used as the
+         *            parent for this dialog.
+         * @param target Specific {@link View} from your layout that this dialog
+         *            should be centered around. In particular, if the dialog
+         *            has a "callout" arrow, it will be pointed and centered
+         *            around this {@link View}.
+         * @param lookupUri A
+         *            {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
+         *            {@link Uri} that describes a specific contact to feature
+         *            in this dialog.
+         * @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
+         *            to exclude when showing this dialog. For example, when
+         *            already viewing the contact details card, this can be used
+         *            to omit the details entry from the dialog.
+         * @param prioritizedMimeType This mimetype should be prioritized in the QuickContacts UI.
+         *             For example, passing the value
+         *             {@link CommonDataKinds.Phone#CONTENT_ITEM_TYPE} can cause phone numbers to be
+         *             displayed more prominently in QuickContacts.
+         */
+        public static void showQuickContact(Context context, View target, Uri lookupUri,
+                String[] excludeMimes, String prioritizedMimeType) {
+            // Use MODE_LARGE instead of accepting mode as a parameter. The different mode
+            // values defined in ContactsContract only affect very old implementations
+            // of QuickContacts.
+            Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_LARGE,
+                    excludeMimes);
+            intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType);
+            startActivityWithErrorToast(context, intent);
+        }
+
+        /**
+         * Trigger a dialog that lists the various methods of interacting with
+         * the requested {@link Contacts} entry. This may be based on available
+         * {@link ContactsContract.Data} rows under that contact, and may also
+         * include social status and presence details.
+         *
+         * @param context The parent {@link Context} that may be used as the
+         *            parent for this dialog.
+         * @param target Specific {@link Rect} that this dialog should be
+         *            centered around, in screen coordinates. In particular, if
+         *            the dialog has a "callout" arrow, it will be pointed and
+         *            centered around this {@link Rect}. If you are running at a
+         *            non-native density, you need to manually adjust using
+         *            {@link DisplayMetrics#density} before calling.
+         * @param lookupUri A
+         *            {@link ContactsContract.Contacts#CONTENT_LOOKUP_URI} style
+         *            {@link Uri} that describes a specific contact to feature
+         *            in this dialog.
+         * @param excludeMimes Optional list of {@link Data#MIMETYPE} MIME-types
+         *            to exclude when showing this dialog. For example, when
+         *            already viewing the contact details card, this can be used
+         *            to omit the details entry from the dialog.
+         * @param prioritizedMimeType This mimetype should be prioritized in the QuickContacts UI.
+         *             For example, passing the value
+         *             {@link CommonDataKinds.Phone#CONTENT_ITEM_TYPE} can cause phone numbers to be
+         *             displayed more prominently in QuickContacts.
+         */
+        public static void showQuickContact(Context context, Rect target, Uri lookupUri,
+                String[] excludeMimes, String prioritizedMimeType) {
+            // Use MODE_LARGE instead of accepting mode as a parameter. The different mode
+            // values defined in ContactsContract only affect very old implementations
+            // of QuickContacts.
+            Intent intent = composeQuickContactsIntent(context, target, lookupUri, MODE_LARGE,
+                    excludeMimes);
+            intent.putExtra(EXTRA_PRIORITIZED_MIMETYPE, prioritizedMimeType);
+            startActivityWithErrorToast(context, intent);
+        }
+
         private static void startActivityWithErrorToast(Context context, Intent intent) {
             try {
               context.startActivity(intent);
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/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index 3492aa0..b49a59e 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -25,8 +25,11 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
@@ -334,6 +337,11 @@
         
         private ActionProvider itemActionProvider;
 
+        private ColorStateList itemIconTintList;
+        private boolean itemIconTintListSet;
+        private PorterDuff.Mode itemIconTintMode;
+        private boolean itemIconTintModeSet;
+
         private static final int defaultGroupId = NO_ID;
         private static final int defaultItemId = NO_ID;
         private static final int defaultItemCategory = 0;
@@ -424,6 +432,23 @@
                 itemActionProvider = null;
             }
 
+            if (a.hasValueOrEmpty(com.android.internal.R.styleable.MenuItem_iconTint)) {
+                itemIconTintList = a.getColorStateList(
+                        com.android.internal.R.styleable.MenuItem_iconTint);
+                itemIconTintListSet = true;
+            } else {
+                itemIconTintList = null;
+                itemIconTintListSet = false;
+            }
+            if (a.hasValueOrEmpty(com.android.internal.R.styleable.MenuItem_iconTintMode)) {
+                itemIconTintMode = Drawable.parseTintMode(
+                        a.getInt(com.android.internal.R.styleable.MenuItem_iconTintMode, -1), null);
+                itemIconTintModeSet = true;
+            } else {
+                itemIconTintMode = null;
+                itemIconTintModeSet = false;
+            }
+
             a.recycle();
 
             itemAdded = false;
@@ -486,6 +511,13 @@
             if (itemActionProvider != null) {
                 item.setActionProvider(itemActionProvider);
             }
+
+            if (itemIconTintListSet) {
+                item.setIconTintList(itemIconTintList);
+            }
+            if (itemIconTintModeSet) {
+                item.setIconTintMode(itemIconTintMode);
+            }
         }
 
         public MenuItem addItem() {
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index 9e8b97e..2948007 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -21,6 +21,8 @@
 import android.annotation.StringRes;
 import android.app.Activity;
 import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.View.OnCreateContextMenuListener;
@@ -599,4 +601,26 @@
      * @return This menu item instance for call chaining
      */
     public MenuItem setOnActionExpandListener(OnActionExpandListener listener);
+
+    /**
+     * Applies a tint to the icon drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     * <p>
+     * Subsequent calls to {@link android.view.MenuItem#setIcon(android.graphics.drawable.Drawable)}
+     * will automatically mutate the drawable and apply the specified tint and tint mode.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     * @return This menu item instance for call chaining
+     */
+    public MenuItem setIconTintList(ColorStateList tint);
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by {@link
+     * #setIconTintList(ColorStateList)} to the icon drawable. The default mode is {@link
+     * PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
+     * @return This menu item instance for call chaining
+     */
+    public MenuItem setIconTintMode(PorterDuff.Mode tintMode);
 }
diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
index 2a25fd2..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.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 502d5ee..6d3c07a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,9 +16,7 @@
 
 package android.view;
 
-import android.animation.Animator;
 import android.animation.AnimatorInflater;
-import android.animation.ObjectAnimator;
 import android.animation.StateListAnimator;
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
@@ -34,10 +32,13 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Insets;
+import android.graphics.Interpolator;
 import android.graphics.LinearGradient;
 import android.graphics.Matrix;
 import android.graphics.Outline;
 import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.PorterDuff;
@@ -4325,7 +4326,9 @@
      * @hide This is the real method; the public one is shimmed to be safe to call from apps.
      */
     protected void initializeFadingEdgeInternal(TypedArray a) {
-        getScrollCache().fadingEdgeLength = a.getDimensionPixelSize(
+        initScrollCache();
+
+        mScrollCache.fadingEdgeLength = a.getDimensionPixelSize(
                 R.styleable.View_fadingEdgeLength,
                 ViewConfiguration.get(mContext).getScaledFadingEdgeLength());
     }
@@ -4359,7 +4362,8 @@
      *        content in this view is visible.
      */
     public void setFadingEdgeLength(int length) {
-        getScrollCache().fadingEdgeLength = length;
+        initScrollCache();
+        mScrollCache.fadingEdgeLength = length;
     }
 
     /**
@@ -4463,7 +4467,10 @@
      * @hide
      */
     protected void initializeScrollbarsInternal(TypedArray a) {
-        final ScrollabilityCache scrollabilityCache = getScrollCache();
+        initScrollCache();
+
+        final ScrollabilityCache scrollabilityCache = mScrollCache;
+
         if (scrollabilityCache.scrollBar == null) {
             scrollabilityCache.scrollBar = new ScrollBarDrawable();
             scrollabilityCache.scrollBar.setCallback(this);
@@ -4471,16 +4478,23 @@
         }
 
         final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true);
-        scrollabilityCache.setFadingEnabled(fadeScrollbars);
+
+        if (!fadeScrollbars) {
+            scrollabilityCache.state = ScrollabilityCache.ON;
+        }
+        scrollabilityCache.fadeScrollBars = fadeScrollbars;
+
 
         scrollabilityCache.scrollBarFadeDuration = a.getInt(
-                R.styleable.View_scrollbarFadeDuration,
-                ViewConfiguration.getScrollBarFadeDuration());
+                R.styleable.View_scrollbarFadeDuration, ViewConfiguration
+                        .getScrollBarFadeDuration());
         scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt(
                 R.styleable.View_scrollbarDefaultDelayBeforeFade,
                 ViewConfiguration.getScrollDefaultDelay());
+
+
         scrollabilityCache.scrollBarSize = a.getDimensionPixelSize(
-                R.styleable.View_scrollbarSize,
+                com.android.internal.R.styleable.View_scrollbarSize,
                 ViewConfiguration.get(mContext).getScaledScrollBarSize());
 
         Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal);
@@ -4525,12 +4539,18 @@
     }
 
     /**
-     * Returns the scrollability cache, initializing a new cache if necessary.
+     * <p>
+     * Initalizes the scrollability cache if necessary.
+     * </p>
      */
-    private ScrollabilityCache getScrollCache() {
+    private void initScrollCache() {
         if (mScrollCache == null) {
-            mScrollCache = new ScrollabilityCache(this);
+            mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this);
         }
+    }
+
+    private ScrollabilityCache getScrollCache() {
+        initScrollCache();
         return mScrollCache;
     }
 
@@ -10047,6 +10067,10 @@
      *
      * @return The measured width of this view as a bit mask.
      */
+    @ViewDebug.ExportedProperty(category = "measurement", flagMapping = {
+            @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL,
+                    name = "MEASURED_STATE_TOO_SMALL"),
+    })
     public final int getMeasuredWidthAndState() {
         return mMeasuredWidth;
     }
@@ -10071,6 +10095,10 @@
      *
      * @return The measured width of this view as a bit mask.
      */
+    @ViewDebug.ExportedProperty(category = "measurement", flagMapping = {
+            @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL,
+                    name = "MEASURED_STATE_TOO_SMALL"),
+    })
     public final int getMeasuredHeightAndState() {
         return mMeasuredHeight;
     }
@@ -11551,30 +11579,31 @@
      * @see #setVerticalScrollBarEnabled(boolean)
      */
     protected boolean awakenScrollBars() {
-        return mScrollCache != null
-                && awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true);
+        return mScrollCache != null &&
+                awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true);
     }
 
     /**
      * Trigger the scrollbars to draw.
-     * <p>
      * This method differs from awakenScrollBars() only in its default duration.
      * initialAwakenScrollBars() will show the scroll bars for longer than
      * usual to give the user more of a chance to notice them.
      *
      * @return true if the animation is played, false otherwise.
-     * @see #awakenScrollBars()
      */
     private boolean initialAwakenScrollBars() {
-        return mScrollCache != null
-                && awakenScrollBars(mScrollCache.scrollBarDelayBeforeInitialFade, true);
+        return mScrollCache != null &&
+                awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true);
     }
 
     /**
+     * <p>
      * Trigger the scrollbars to draw. When invoked this method starts an
      * animation to fade the scrollbars out after a fixed delay. If a subclass
      * provides animated scrolling, the start delay should equal the duration of
      * the scrolling animation.
+     * </p>
+     *
      * <p>
      * The animation starts only if at least one of the scrollbars is enabled,
      * as specified by {@link #isHorizontalScrollBarEnabled()} and
@@ -11582,14 +11611,18 @@
      * this method returns true, and false otherwise. If the animation is
      * started, this method calls {@link #invalidate()}; in that case the caller
      * should not call {@link #invalidate()}.
+     * </p>
+     *
      * <p>
      * This method should be invoked every time a subclass directly updates the
      * scroll parameters.
+     * </p>
      *
-     * @param fadeOutDelay the delay in milliseconds before the fade out
-     *                     animation should start, or 0 to start the animation
-     *                     immediately
+     * @param startDelay the delay, in milliseconds, after which the animation
+     *        should start; when the delay is 0, the animation starts
+     *        immediately
      * @return true if the animation is played, false otherwise
+     *
      * @see #scrollBy(int, int)
      * @see #scrollTo(int, int)
      * @see #isHorizontalScrollBarEnabled()
@@ -11597,15 +11630,18 @@
      * @see #setHorizontalScrollBarEnabled(boolean)
      * @see #setVerticalScrollBarEnabled(boolean)
      */
-    protected boolean awakenScrollBars(int fadeOutDelay) {
-        return awakenScrollBars(fadeOutDelay, true);
+    protected boolean awakenScrollBars(int startDelay) {
+        return awakenScrollBars(startDelay, true);
     }
 
     /**
+     * <p>
      * Trigger the scrollbars to draw. When invoked this method starts an
      * animation to fade the scrollbars out after a fixed delay. If a subclass
      * provides animated scrolling, the start delay should equal the duration of
      * the scrolling animation.
+     * </p>
+     *
      * <p>
      * The animation starts only if at least one of the scrollbars is enabled,
      * as specified by {@link #isHorizontalScrollBarEnabled()} and
@@ -11614,18 +11650,21 @@
      * started, this method calls {@link #invalidate()} if the invalidate parameter
      * is set to true; in that case the caller
      * should not call {@link #invalidate()}.
+     * </p>
+     *
      * <p>
      * This method should be invoked every time a subclass directly updates the
      * scroll parameters.
-     * <p>
-     * <strong>Note:</strong> If the view has not explicitly requested
-     * scrollbars prior calling this method, this is a no-op.
+     * </p>
      *
-     * @param fadeOutDelay the delay in milliseconds before the fade out
-     *                     animation should start, or 0 to start the animation
-     *                     immediately
-     * @param invalidate whether this method should call invalidate
+     * @param startDelay the delay, in milliseconds, after which the animation
+     *        should start; when the delay is 0, the animation starts
+     *        immediately
+     *
+     * @param invalidate Whether this method should call invalidate
+     *
      * @return true if the animation is played, false otherwise
+     *
      * @see #scrollBy(int, int)
      * @see #scrollTo(int, int)
      * @see #isHorizontalScrollBarEnabled()
@@ -11633,15 +11672,50 @@
      * @see #setHorizontalScrollBarEnabled(boolean)
      * @see #setVerticalScrollBarEnabled(boolean)
      */
-    protected boolean awakenScrollBars(int fadeOutDelay, boolean invalidate) {
-        if (mScrollCache == null
-                || (!isHorizontalScrollBarEnabled() && !isVerticalScrollBarEnabled())) {
-            // We're not supposed to show scroll bars right now.
+    protected boolean awakenScrollBars(int startDelay, boolean invalidate) {
+        final ScrollabilityCache scrollCache = mScrollCache;
+
+        if (scrollCache == null || !scrollCache.fadeScrollBars) {
             return false;
         }
 
-        mScrollCache.awakenScrollBars(fadeOutDelay);
-        return true;
+        if (scrollCache.scrollBar == null) {
+            scrollCache.scrollBar = new ScrollBarDrawable();
+            scrollCache.scrollBar.setCallback(this);
+            scrollCache.scrollBar.setState(getDrawableState());
+        }
+
+        if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) {
+
+            if (invalidate) {
+                // Invalidate to show the scrollbars
+                postInvalidateOnAnimation();
+            }
+
+            if (scrollCache.state == ScrollabilityCache.OFF) {
+                // FIXME: this is copied from WindowManagerService.
+                // We should get this value from the system when it
+                // is possible to do so.
+                final int KEY_REPEAT_FIRST_DELAY = 750;
+                startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay);
+            }
+
+            // Tell mScrollCache when we should start fading. This may
+            // extend the fade start time if one was already scheduled
+            long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay;
+            scrollCache.fadeStartTime = fadeStartTime;
+            scrollCache.state = ScrollabilityCache.ON;
+
+            // Schedule our fader to run, unscheduling any old ones first
+            if (mAttachInfo != null) {
+                mAttachInfo.mHandler.removeCallbacks(scrollCache);
+                mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime);
+            }
+
+            return true;
+        }
+
+        return false;
     }
 
     /**
@@ -12322,7 +12396,7 @@
     public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) {
         if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) {
             if (horizontalFadingEdgeEnabled) {
-                getScrollCache();
+                initScrollCache();
             }
 
             mViewFlags ^= FADING_EDGE_HORIZONTAL;
@@ -12359,7 +12433,7 @@
     public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) {
         if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) {
             if (verticalFadingEdgeEnabled) {
-                getScrollCache();
+                initScrollCache();
             }
 
             mViewFlags ^= FADING_EDGE_VERTICAL;
@@ -12499,7 +12573,14 @@
      * @attr ref android.R.styleable#View_fadeScrollbars
      */
     public void setScrollbarFadingEnabled(boolean fadeScrollbars) {
-        getScrollCache().setFadingEnabled(fadeScrollbars);
+        initScrollCache();
+        final ScrollabilityCache scrollabilityCache = mScrollCache;
+        scrollabilityCache.fadeScrollBars = fadeScrollbars;
+        if (fadeScrollbars) {
+            scrollabilityCache.state = ScrollabilityCache.OFF;
+        } else {
+            scrollabilityCache.state = ScrollabilityCache.ON;
+        }
     }
 
     /**
@@ -12511,7 +12592,7 @@
      * @attr ref android.R.styleable#View_fadeScrollbars
      */
     public boolean isScrollbarFadingEnabled() {
-        return mScrollCache != null && mScrollCache.isFadingEnabled();
+        return mScrollCache != null && mScrollCache.fadeScrollBars;
     }
 
     /**
@@ -12793,85 +12874,129 @@
     }
 
     /**
-     * Request the drawing of the horizontal and the vertical scrollbar. The
-     * scrollbars are painted only if they have been awakened first.
+     * <p>Request the drawing of the horizontal and the vertical scrollbar. The
+     * scrollbars are painted only if they have been awakened first.</p>
      *
      * @param canvas the canvas on which to draw the scrollbars
+     *
      * @see #awakenScrollBars(int)
      */
     protected final void onDrawScrollBars(Canvas canvas) {
+        // scrollbars are drawn only when the animation is running
         final ScrollabilityCache cache = mScrollCache;
-        if (cache == null) {
-            // This view does not currently support scrolling.
-            return;
-        }
+        if (cache != null) {
 
-        final int viewFlags = mViewFlags;
-        final boolean drawHorizontalScrollBar =
-            (viewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL;
-        final boolean drawVerticalScrollBar =
-            (viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL
-            && !isVerticalScrollBarHidden();
-        if (!drawVerticalScrollBar && !drawHorizontalScrollBar) {
-            // This view does not currently draw scrollbars.
-            return;
-        }
+            int state = cache.state;
 
-        final ScrollBarDrawable scrollBar = cache.scrollBar;
-        final int width = mRight - mLeft;
-        final int height = mBottom - mTop;
-        final int scrollX = mScrollX;
-        final int scrollY = mScrollY;
-        final int inside = (viewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
-
-        if (drawHorizontalScrollBar) {
-            int size = scrollBar.getSize(false);
-            if (size <= 0) {
-                size = cache.scrollBarSize;
+            if (state == ScrollabilityCache.OFF) {
+                return;
             }
 
-            scrollBar.setParameters(computeHorizontalScrollRange(), computeHorizontalScrollOffset(),
-                    computeHorizontalScrollExtent(), false);
-            final int verticalScrollBarGap = drawVerticalScrollBar ?
-                    getVerticalScrollbarWidth() : 0;
+            boolean invalidate = false;
 
-            final int left = scrollX + (mPaddingLeft & inside);
-            final int right = scrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap;
-            final int top = scrollY + height - size - (mUserPaddingBottom & inside);
-            final int bottom = top + size;
+            if (state == ScrollabilityCache.FADING) {
+                // We're fading -- get our fade interpolation
+                if (cache.interpolatorValues == null) {
+                    cache.interpolatorValues = new float[1];
+                }
 
-            onDrawHorizontalScrollBar(canvas, scrollBar, left, top, right, bottom);
-        }
+                float[] values = cache.interpolatorValues;
 
-        if (drawVerticalScrollBar) {
-            int size = scrollBar.getSize(true);
-            if (size <= 0) {
-                size = cache.scrollBarSize;
-            }
+                // Stops the animation if we're done
+                if (cache.scrollBarInterpolator.timeToValues(values) ==
+                        Interpolator.Result.FREEZE_END) {
+                    cache.state = ScrollabilityCache.OFF;
+                } else {
+                    cache.scrollBar.mutate().setAlpha(Math.round(values[0]));
+                }
 
-            scrollBar.setParameters(computeVerticalScrollRange(), computeVerticalScrollOffset(),
-                    computeVerticalScrollExtent(), true);
-
-            final int verticalScrollbarPosition;
-            if (mVerticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) {
-                verticalScrollbarPosition = isLayoutRtl() ?
-                        SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT;
+                // This will make the scroll bars inval themselves after
+                // drawing. We only want this when we're fading so that
+                // we prevent excessive redraws
+                invalidate = true;
             } else {
-                verticalScrollbarPosition = mVerticalScrollbarPosition;
+                // We're just on -- but we may have been fading before so
+                // reset alpha
+                cache.scrollBar.mutate().setAlpha(255);
             }
 
-            final int left;
-            if (verticalScrollbarPosition == SCROLLBAR_POSITION_LEFT) {
-                left = scrollX + (mUserPaddingLeft & inside);
-            } else {
-                left = scrollX + width - size - (mUserPaddingRight & inside);
+
+            final int viewFlags = mViewFlags;
+
+            final boolean drawHorizontalScrollBar =
+                (viewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL;
+            final boolean drawVerticalScrollBar =
+                (viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL
+                && !isVerticalScrollBarHidden();
+
+            if (drawVerticalScrollBar || drawHorizontalScrollBar) {
+                final int width = mRight - mLeft;
+                final int height = mBottom - mTop;
+
+                final ScrollBarDrawable scrollBar = cache.scrollBar;
+
+                final int scrollX = mScrollX;
+                final int scrollY = mScrollY;
+                final int inside = (viewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
+
+                int left;
+                int top;
+                int right;
+                int bottom;
+
+                if (drawHorizontalScrollBar) {
+                    int size = scrollBar.getSize(false);
+                    if (size <= 0) {
+                        size = cache.scrollBarSize;
+                    }
+
+                    scrollBar.setParameters(computeHorizontalScrollRange(),
+                                            computeHorizontalScrollOffset(),
+                                            computeHorizontalScrollExtent(), false);
+                    final int verticalScrollBarGap = drawVerticalScrollBar ?
+                            getVerticalScrollbarWidth() : 0;
+                    top = scrollY + height - size - (mUserPaddingBottom & inside);
+                    left = scrollX + (mPaddingLeft & inside);
+                    right = scrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap;
+                    bottom = top + size;
+                    onDrawHorizontalScrollBar(canvas, scrollBar, left, top, right, bottom);
+                    if (invalidate) {
+                        invalidate(left, top, right, bottom);
+                    }
+                }
+
+                if (drawVerticalScrollBar) {
+                    int size = scrollBar.getSize(true);
+                    if (size <= 0) {
+                        size = cache.scrollBarSize;
+                    }
+
+                    scrollBar.setParameters(computeVerticalScrollRange(),
+                                            computeVerticalScrollOffset(),
+                                            computeVerticalScrollExtent(), true);
+                    int verticalScrollbarPosition = mVerticalScrollbarPosition;
+                    if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) {
+                        verticalScrollbarPosition = isLayoutRtl() ?
+                                SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT;
+                    }
+                    switch (verticalScrollbarPosition) {
+                        default:
+                        case SCROLLBAR_POSITION_RIGHT:
+                            left = scrollX + width - size - (mUserPaddingRight & inside);
+                            break;
+                        case SCROLLBAR_POSITION_LEFT:
+                            left = scrollX + (mUserPaddingLeft & inside);
+                            break;
+                    }
+                    top = scrollY + (mPaddingTop & inside);
+                    right = left + size;
+                    bottom = scrollY + height - (mUserPaddingBottom & inside);
+                    onDrawVerticalScrollBar(canvas, scrollBar, left, top, right, bottom);
+                    if (invalidate) {
+                        invalidate(left, top, right, bottom);
+                    }
+                }
             }
-
-            final int top = scrollY + (mPaddingTop & inside);
-            final int right = left + size;
-            final int bottom = scrollY + height - (mUserPaddingBottom & inside);
-
-            onDrawVerticalScrollBar(canvas, scrollBar, left, top, right, bottom);
         }
     }
 
@@ -12978,7 +13103,9 @@
 
         if (isFocused()) {
             InputMethodManager imm = InputMethodManager.peekInstance();
-            imm.focusIn(this);
+            if (imm != null) {
+                imm.focusIn(this);
+            }
         }
     }
 
@@ -15235,7 +15362,7 @@
                 canvas.saveLayer(right - length, top, right, bottom, null, flags);
             }
         } else {
-            scrollabilityCache.setFadingEdgeColor(solidColor);
+            scrollabilityCache.setFadeColor(solidColor);
         }
 
         // Step 3, draw the content
@@ -15245,9 +15372,9 @@
         dispatchDraw(canvas);
 
         // Step 5, draw the fade effect and restore layers
-        final Paint p = scrollabilityCache.fadingEdgePaint;
+        final Paint p = scrollabilityCache.paint;
         final Matrix matrix = scrollabilityCache.matrix;
-        final Shader fade = scrollabilityCache.fadingEdgeShader;
+        final Shader fade = scrollabilityCache.shader;
 
         if (drawTop) {
             matrix.setScale(1, fadeHeight * topFadeStrength);
@@ -20507,164 +20634,121 @@
     }
 
     /**
-     * ScrollabilityCache holds various fields used by a View when scrolling
+     * <p>ScrollabilityCache holds various fields used by a View when scrolling
      * is supported. This avoids keeping too many unused fields in most
-     * instances of View.
+     * instances of View.</p>
      */
-    private static class ScrollabilityCache {
-        public final Paint fadingEdgePaint = new Paint();
-        public final Matrix matrix = new Matrix();
-
-        /** The view that owns this cache. */
-        private final View mHost;
+    private static class ScrollabilityCache implements Runnable {
 
         /**
-         * Minimum delay in milliseconds before the fade-out animation begins.
-         * Only used if the scrollbar was previously invisible.
+         * Scrollbars are not visible
          */
-        private static final int MIN_FADE_DELAY_FROM_OFF = 750;
+        public static final int OFF = 0;
 
         /**
-         * Default delay in milliseconds before the fade-out animation begins.
+         * Scrollbars are visible
          */
+        public static final int ON = 1;
+
+        /**
+         * Scrollbars are fading away
+         */
+        public static final int FADING = 2;
+
+        public boolean fadeScrollBars;
+
+        public int fadingEdgeLength;
         public int scrollBarDefaultDelayBeforeFade;
-
-        /**
-         * Delay in milliseconds before the fade-out animation begins. Only
-         * used if the scrollbar is being shown to the user for the first time.
-         */
-        public int scrollBarDelayBeforeInitialFade;
-
-        /** Duration in milliseconds of the fade-out animation. */
         public int scrollBarFadeDuration;
 
-        public ScrollBarDrawable scrollBar;
-        public Shader fadingEdgeShader;
-        public int fadingEdgeLength;
         public int scrollBarSize;
+        public ScrollBarDrawable scrollBar;
+        public float[] interpolatorValues;
+        public View host;
+
+        public final Paint paint;
+        public final Matrix matrix;
+        public Shader shader;
+
+        public final Interpolator scrollBarInterpolator = new Interpolator(1, 2);
+
+        private static final float[] OPAQUE = { 255 };
+        private static final float[] TRANSPARENT = { 0.0f };
 
         /**
-         * Whether scrollbar fading is enabled. If false, scrollbars are always
-         * visible.
+         * When fading should start. This time moves into the future every time
+         * a new scroll happens. Measured based on SystemClock.uptimeMillis()
          */
-        private boolean mIsFadingEnabled;
+        public long fadeStartTime;
 
-        private Animator mFadeAnim;
-        private int mFadingEdgeLastColor;
 
-        public ScrollabilityCache(View host) {
-            mHost = host;
+        /**
+         * The current state of the scrollbars: ON, OFF, or FADING
+         */
+        public int state = OFF;
 
-            scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration();
-            scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay();
-            scrollBarDelayBeforeInitialFade = ViewConfiguration.getScrollDefaultInitialDelay();
+        private int mLastColor;
 
-            final ViewConfiguration configuration = ViewConfiguration.get(host.getContext());
-            scrollBarSize = configuration.getScaledScrollBarSize();
+        public ScrollabilityCache(ViewConfiguration configuration, View host) {
             fadingEdgeLength = configuration.getScaledFadingEdgeLength();
+            scrollBarSize = configuration.getScaledScrollBarSize();
+            scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay();
+            scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration();
 
-            // Force the fading edge color to change.
-            mFadingEdgeLastColor = -1;
-            setFadingEdgeColor(0);
+            paint = new Paint();
+            matrix = new Matrix();
+            // use use a height of 1, and then wack the matrix each time we
+            // actually use it.
+            shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP);
+            paint.setShader(shader);
+            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+
+            this.host = host;
         }
 
-        public void setFadingEdgeColor(int color) {
-            if (mFadingEdgeLastColor != color) {
-                mFadingEdgeLastColor = color;
+        public void setFadeColor(int color) {
+            if (color != mLastColor) {
+                mLastColor = color;
 
-                final int color0;
-                final int color1;
-                final PorterDuffXfermode xfermode;
                 if (color != 0) {
-                    color0 = color | 0xFF000000;
-                    color1 = color & 0x00FFFFFF;
-                    xfermode = null;
+                    shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000,
+                            color & 0x00FFFFFF, Shader.TileMode.CLAMP);
+                    paint.setShader(shader);
+                    // Restore the default transfer mode (src_over)
+                    paint.setXfermode(null);
                 } else {
-                    color0 = 0xFF000000;
-                    color1 = 0;
-                    xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
+                    shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP);
+                    paint.setShader(shader);
+                    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
                 }
-
-                // Use a height of 1 and then whack the matrix each time we
-                // actually use it.
-                fadingEdgeShader = new LinearGradient(
-                        0, 0, 0, 1, color0, color1, Shader.TileMode.CLAMP);
-                fadingEdgePaint.setShader(fadingEdgeShader);
-                fadingEdgePaint.setXfermode(xfermode);
             }
         }
 
-        public void setFadingEnabled(boolean enabled) {
-            if (mIsFadingEnabled != enabled) {
-                mIsFadingEnabled = enabled;
+        public void run() {
+            long now = AnimationUtils.currentAnimationTimeMillis();
+            if (now >= fadeStartTime) {
 
-                setFadingAlpha(enabled ? 0 : 255);
+                // the animation fades the scrollbars out by changing
+                // the opacity (alpha) from fully opaque to fully
+                // transparent
+                int nextFrame = (int) now;
+                int framesCount = 0;
+
+                Interpolator interpolator = scrollBarInterpolator;
+
+                // Start opaque
+                interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE);
+
+                // End transparent
+                nextFrame += scrollBarFadeDuration;
+                interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT);
+
+                state = FADING;
+
+                // Kick off the fade animation
+                host.invalidate(true);
             }
         }
-
-        public boolean isFadingEnabled() {
-            return mIsFadingEnabled;
-        }
-
-        /**
-         * Cancels any ongoing or pending fade animations and immediately sets
-         * the scroll bar alpha value.
-         *
-         * @param alpha the scrollbar alpha value
-         */
-        public void setFadingAlpha(int alpha) {
-            if (mFadeAnim != null) {
-                mFadeAnim.cancel();
-                mFadeAnim = null;
-            }
-            mHost.removeCallbacks(mFadeOutRunnable);
-
-            scrollBar.setAlpha(alpha);
-        }
-
-        /**
-         * If fading is enabled, cancels any ongoing or pending fade animations
-         * and immediately sets the scroll bar alpha value to the maximum, then
-         * posts a delayed fade-out animation.
-         *
-         * @param fadeOutDelay the delay before the fade-out animation starts
-         * @return {@code true} if the scroll bars changed, false otherwise
-         */
-        public boolean awakenScrollBars(int fadeOutDelay) {
-            if (!mIsFadingEnabled) {
-                return false;
-            }
-
-            if (scrollBar == null) {
-                scrollBar = new ScrollBarDrawable();
-                scrollBar.setCallback(mHost);
-                scrollBar.setState(mHost.getDrawableState());
-            }
-
-            // Removes pending callbacks.
-            setFadingAlpha(255);
-
-            final int startingAlpha = scrollBar.getAlpha();
-            if (startingAlpha == 0) {
-                fadeOutDelay = Math.max(ScrollabilityCache.MIN_FADE_DELAY_FROM_OFF, fadeOutDelay);
-            }
-
-            mHost.postDelayed(mFadeOutRunnable, fadeOutDelay);
-
-            return true;
-        }
-
-        private final Runnable mFadeOutRunnable = new Runnable() {
-            @Override
-            public void run() {
-                final ObjectAnimator anim = ObjectAnimator.ofInt(
-                        scrollBar, ScrollBarDrawable.ALPHA, 0);
-                anim.setDuration(scrollBarFadeDuration);
-                anim.start();
-
-                mFadeAnim = anim;
-            }
-        };
     }
 
     /**
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index d733513..4e91ad4 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -47,12 +47,6 @@
     private static final int SCROLL_BAR_DEFAULT_DELAY = 300;
 
     /**
-     * Default delay before the scrollbars fade in milliseconds for the first
-     * time they are shown to the user.
-     */
-    private static final int SCROLL_BAR_DEFAULT_INITIAL_DELAY = 1500;
-
-    /**
      * Defines the length of the fading edges in dips
      */
     private static final int FADING_EDGE_LENGTH = 12;
@@ -401,23 +395,13 @@
     }
 
     /**
-     * @return Default delay in milliseconds before the scrollbars fade out
-     *         after they have been awoken.
+     * @return Default delay before the scrollbars fade in milliseconds
      */
     public static int getScrollDefaultDelay() {
         return SCROLL_BAR_DEFAULT_DELAY;
     }
 
     /**
-     * @return Default delay in milliseconds before the scrollbars fade out
-     *         after they are initially shown to the user.
-     * @hide Pending cleanup of ViewConfiguration values.
-     */
-    public static int getScrollDefaultInitialDelay() {
-        return SCROLL_BAR_DEFAULT_INITIAL_DELAY;
-    }
-
-    /**
      * @return the length of the fading edges in dips
      *
      * @deprecated Use {@link #getScaledFadingEdgeLength()} instead.
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 79ad6e3..1892184 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -403,23 +403,26 @@
     }
 
     private void updateThumbAndTrackPos(int w, int h) {
+        final int paddedHeight = h - mPaddingTop - mPaddingBottom;
         final Drawable track = getCurrentDrawable();
         final Drawable thumb = mThumb;
 
         // The max height does not incorporate padding, whereas the height
         // parameter does.
-        final int trackHeight = Math.min(mMaxHeight, h - mPaddingTop - mPaddingBottom);
+        final int trackHeight = Math.min(mMaxHeight, paddedHeight);
         final int thumbHeight = thumb == null ? 0 : thumb.getIntrinsicHeight();
 
         // Apply offset to whichever item is taller.
         final int trackOffset;
         final int thumbOffset;
         if (thumbHeight > trackHeight) {
-            trackOffset = (thumbHeight - trackHeight) / 2;
-            thumbOffset = 0;
+            final int offsetHeight = (paddedHeight - thumbHeight) / 2;
+            trackOffset = offsetHeight + (thumbHeight - trackHeight) / 2;
+            thumbOffset = offsetHeight + 0;
         } else {
-            trackOffset = 0;
-            thumbOffset = (trackHeight - thumbHeight) / 2;
+            final int offsetHeight = (paddedHeight - trackHeight) / 2;
+            trackOffset = offsetHeight + 0;
+            thumbOffset = offsetHeight + (trackHeight - thumbHeight) / 2;
         }
 
         if (track != null) {
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index 94827dd..4fadc19 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -17,10 +17,10 @@
 package android.widget;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Matrix;
-import android.graphics.Rect;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -55,7 +55,7 @@
         implements ActionProvider.SubUiVisibilityListener {
     private static final String TAG = "ActionMenuPresenter";
 
-    private View mOverflowButton;
+    private OverflowMenuButton mOverflowButton;
     private boolean mReserveOverflow;
     private boolean mReserveOverflowSet;
     private int mWidthLimit;
@@ -79,6 +79,8 @@
     private OpenOverflowRunnable mPostedOpenRunnable;
     private ActionMenuPopupCallback mPopupCallback;
 
+    private TintInfo mOverflowTintInfo;
+
     final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
     int mOpenSubMenuId;
 
@@ -113,6 +115,7 @@
                 mOverflowButton = new OverflowMenuButton(mSystemContext);
                 final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
                 mOverflowButton.measure(spec, spec);
+                applyOverflowTint();
             }
             width -= mOverflowButton.getMeasuredWidth();
         } else {
@@ -236,6 +239,7 @@
         if (hasOverflow) {
             if (mOverflowButton == null) {
                 mOverflowButton = new OverflowMenuButton(mSystemContext);
+                applyOverflowTint();
             }
             ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
             if (parent != mMenuView) {
@@ -550,6 +554,40 @@
         menuView.initialize(mMenu);
     }
 
+    public void setOverflowTintList(ColorStateList tint) {
+        if (mOverflowTintInfo == null) {
+            mOverflowTintInfo = new TintInfo();
+        }
+        mOverflowTintInfo.mTintList = tint;
+        mOverflowTintInfo.mHasTintList = true;
+
+        applyOverflowTint();
+    }
+
+    public void setOverflowTintMode(PorterDuff.Mode tintMode) {
+        if (mOverflowTintInfo == null) {
+            mOverflowTintInfo = new TintInfo();
+        }
+        mOverflowTintInfo.mTintMode = tintMode;
+        mOverflowTintInfo.mHasTintMode = true;
+
+        applyOverflowTint();
+    }
+
+    private void applyOverflowTint() {
+        final TintInfo tintInfo = mOverflowTintInfo;
+        if (tintInfo != null && (tintInfo.mHasTintList || tintInfo.mHasTintMode)) {
+            if (mOverflowButton != null) {
+                if (tintInfo.mHasTintList) {
+                    mOverflowButton.setImageTintList(tintInfo.mTintList);
+                }
+                if (tintInfo.mHasTintMode) {
+                    mOverflowButton.setImageTintMode(tintInfo.mTintMode);
+                }
+            }
+        }
+    }
+
     private static class SavedState implements Parcelable {
         public int openSubMenuId;
 
@@ -774,4 +812,11 @@
             return mActionButtonPopup != null ? mActionButtonPopup.getPopup() : null;
         }
     }
+
+    private static class TintInfo {
+        ColorStateList mTintList;
+        PorterDuff.Mode mTintMode;
+        boolean mHasTintMode;
+        boolean mHasTintList;
+    }
 }
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 403e4ac..9d3a5dc 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -16,7 +16,9 @@
 package android.widget;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
+import android.graphics.PorterDuff;
 import android.util.AttributeSet;
 import android.view.ContextThemeWrapper;
 import android.view.Gravity;
@@ -546,6 +548,31 @@
         mReserveOverflow = reserveOverflow;
     }
 
+    /**
+     * Applies a tint to the overflow drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     */
+    public void setOverflowTintList(ColorStateList tint) {
+        if (mPresenter != null) {
+            mPresenter.setOverflowTintList(tint);
+        }
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by {@link
+     * #setOverflowTintList(ColorStateList)} to the overflow drawable.
+     * The default mode is {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
+     */
+    public void setOverflowTintMode(PorterDuff.Mode tintMode) {
+        if (mPresenter != null) {
+            mPresenter.setOverflowTintMode(tintMode);
+        }
+    }
+
     @Override
     protected LayoutParams generateDefaultLayoutParams() {
         LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
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..3568522
--- 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,
@@ -154,34 +154,23 @@
 
         dateLayout.setBackground(a.getDrawable(R.styleable.DatePicker_headerBackground));
 
-        final int headerSelectedTextColor = a.getColor(
-                R.styleable.DatePicker_headerSelectedTextColor, defaultHighlightColor);
         final int monthTextAppearanceResId = a.getResourceId(
                 R.styleable.DatePicker_headerMonthTextAppearance, 0);
         if (monthTextAppearanceResId != 0) {
             mHeaderMonthTextView.setTextAppearance(context, monthTextAppearanceResId);
         }
-        mHeaderMonthTextView.setTextColor(ColorStateList.addFirstIfMissing(
-                mHeaderMonthTextView.getTextColors(), R.attr.state_selected,
-                headerSelectedTextColor));
 
         final int dayOfMonthTextAppearanceResId = a.getResourceId(
                 R.styleable.DatePicker_headerDayOfMonthTextAppearance, 0);
         if (dayOfMonthTextAppearanceResId != 0) {
             mHeaderDayOfMonthTextView.setTextAppearance(context, dayOfMonthTextAppearanceResId);
         }
-        mHeaderDayOfMonthTextView.setTextColor(ColorStateList.addFirstIfMissing(
-                mHeaderDayOfMonthTextView.getTextColors(), R.attr.state_selected,
-                headerSelectedTextColor));
 
         final int headerYearTextAppearanceResId = a.getResourceId(
                 R.styleable.DatePicker_headerYearTextAppearance, 0);
         if (headerYearTextAppearanceResId != 0) {
             mHeaderYearTextView.setTextAppearance(context, headerYearTextAppearanceResId);
         }
-        mHeaderYearTextView.setTextColor(ColorStateList.addFirstIfMissing(
-                mHeaderYearTextView.getTextColors(), R.attr.state_selected,
-                headerSelectedTextColor));
 
         mDayPickerView = new DayPickerView(mContext);
         mDayPickerView.setFirstDayOfWeek(mFirstDayOfWeek);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 1ba11da..8601d2b 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4199,13 +4199,6 @@
     }
 
     /**
-     * @return True iff (start, end) is a valid range within the text.
-     */
-    private static boolean isValidRange(CharSequence text, int start, int end) {
-        return 0 <= start && start <= end && end <= text.length();
-    }
-
-    /**
      * An InputFilter that monitors text input to maintain undo history. It does not modify the
      * text being typed (and hence always returns null from the filter() method).
      */
@@ -4220,123 +4213,97 @@
         public CharSequence filter(CharSequence source, int start, int end,
                 Spanned dest, int dstart, int dend) {
             if (DEBUG_UNDO) {
-                Log.d(TAG, "filter: source=" + source + " (" + start + "-" + end + ") " +
-                        "dest=" + dest + " (" + dstart + "-" + dend + ")");
+                Log.d(TAG, "filter: source=" + source + " (" + start + "-" + end + ")");
+                Log.d(TAG, "filter: dest=" + dest + " (" + dstart + "-" + dend + ")");
             }
             final UndoManager um = mEditor.mUndoManager;
             if (um.isInUndo()) {
-                if (DEBUG_UNDO) Log.d(TAG, "filter: skipping, currently performing undo/redo");
+                if (DEBUG_UNDO) Log.d(TAG, "*** skipping, currently performing undo/redo");
                 return null;
             }
 
-            // Text filters run before input operations are applied. However, some input operations
-            // are invalid and will throw exceptions when applied. This is common in tests. Don't
-            // attempt to undo invalid operations.
-            if (!isValidRange(source, start, end) || !isValidRange(dest, dstart, dend)) {
-                if (DEBUG_UNDO) Log.d(TAG, "filter: invalid op");
-                return null;
-            }
-
-            // Earlier filters can rewrite input to be a no-op, for example due to a length limit
-            // on an input field. Skip no-op changes.
-            if (start == end && dstart == dend) {
-                if (DEBUG_UNDO) Log.d(TAG, "filter: skipping no-op");
-                return null;
-            }
-
-            // Build a new operation with all the information from this edit.
-            EditOperation edit = new EditOperation(mEditor, source, start, end, dest, dstart, dend);
-
-            // Fetch the last edit operation and attempt to merge in the new edit.
             um.beginUpdate("Edit text");
-            EditOperation lastEdit = um.getLastOperation(
-                  EditOperation.class, mEditor.mUndoOwner, UndoManager.MERGE_MODE_UNIQUE);
-            if (lastEdit == null) {
-                // Add this as the first edit.
-                if (DEBUG_UNDO) Log.d(TAG, "filter: adding first op " + edit);
-                um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
-            } else if (lastEdit.mergeWith(edit)) {
-                // Merge succeeded, nothing else to do.
-                if (DEBUG_UNDO) Log.d(TAG, "filter: merge succeeded, created " + lastEdit);
-            } else {
-                // Could not merge with the last edit, so commit the last edit and add this edit.
-                if (DEBUG_UNDO) Log.d(TAG, "filter: merge failed, adding " + edit);
-                um.commitState(mEditor.mUndoOwner);
-                um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
+            TextModifyOperation op = um.getLastOperation(
+                    TextModifyOperation.class, mEditor.mUndoOwner, UndoManager.MERGE_MODE_UNIQUE);
+            if (op != null) {
+                if (DEBUG_UNDO) Log.d(TAG, "Last op: range=(" + op.mRangeStart + "-" + op.mRangeEnd
+                        + "), oldText=" + op.mOldText);
+                // See if we can continue modifying this operation.
+                if (op.mOldText == null) {
+                    // The current operation is an add...  are we adding more?  We are adding
+                    // more if we are either appending new text to the end of the last edit or
+                    // completely replacing some or all of the last edit.
+                    // TODO: This sequence doesn't work right: a, left-arrow, b, undo, undo.
+                    // The two edits are incorrectly merged, so there is only one undo available.
+                    if (start < end && ((dstart >= op.mRangeStart && dend <= op.mRangeEnd)
+                            || (dstart == op.mRangeEnd && dend == op.mRangeEnd))) {
+                        op.mRangeEnd = dstart + (end-start);
+                        um.endUpdate();
+                        if (DEBUG_UNDO) Log.d(TAG, "*** merging with last op, mRangeEnd="
+                                + op.mRangeEnd);
+                        return null;
+                    }
+                } else {
+                    // The current operation is a delete...  can we delete more?
+                    if (start == end && dend == op.mRangeStart-1) {
+                        SpannableStringBuilder str;
+                        if (op.mOldText instanceof SpannableString) {
+                            str = (SpannableStringBuilder)op.mOldText;
+                        } else {
+                            str = new SpannableStringBuilder(op.mOldText);
+                        }
+                        str.insert(0, dest, dstart, dend);
+                        op.mRangeStart = dstart;
+                        op.mOldText = str;
+                        um.endUpdate();
+                        if (DEBUG_UNDO) Log.d(TAG, "*** merging with last op, range=("
+                                + op.mRangeStart + "-" + op.mRangeEnd
+                                + "), oldText=" + op.mOldText);
+                        return null;
+                    }
+                }
+
+                // Couldn't add to the current undo operation, need to start a new
+                // undo state for a new undo operation.
+                um.commitState(null);
+                um.setUndoLabel("Edit text");
             }
+
+            // Create a new undo state reflecting the operation being performed.
+            op = new TextModifyOperation(mEditor.mUndoOwner);
+            op.mRangeStart = dstart;
+            if (start < end) {
+                op.mRangeEnd = dstart + (end-start);
+            } else {
+                op.mRangeEnd = dstart;
+            }
+            if (dstart < dend) {
+                op.mOldText = dest.subSequence(dstart, dend);
+            }
+            if (DEBUG_UNDO) Log.d(TAG, "*** adding new op, range=(" + op.mRangeStart
+                    + "-" + op.mRangeEnd + "), oldText=" + op.mOldText);
+            um.addOperation(op, UndoManager.MERGE_MODE_NONE);
             um.endUpdate();
-            return null;  // Text not changed.
+            return null;
         }
     }
 
     /**
      * An operation to undo a single "edit" to a text view.
      */
-    public static class EditOperation extends UndoOperation<Editor> {
-        private static final int TYPE_INSERT = 0;
-        private static final int TYPE_DELETE = 1;
-        private static final int TYPE_REPLACE = 2;
+    public static class TextModifyOperation extends UndoOperation<Editor> {
+        int mRangeStart, mRangeEnd;
+        CharSequence mOldText;
 
-        private int mType;
-        private String mOldText;
-        private int mOldTextStart;
-        private String mNewText;
-        private int mNewTextStart;
-
-        private int mOldCursorPos;
-        private int mNewCursorPos;
-
-        /**
-         * Constructs an edit operation from a text input operation that replaces the range
-         * (dstart, dend) of dest with (start, end) of source. See {@link InputFilter#filter}.
-         */
-        public EditOperation(Editor editor, CharSequence source, int start, int end,
-                Spanned dest, int dstart, int dend) {
-            super(editor.mUndoOwner);
-
-            mOldText = dest.subSequence(dstart, dend).toString();
-            mNewText = source.subSequence(start, end).toString();
-
-            // Determine the type of the edit and store where it occurred. Avoid storing
-            // irrevelant data (e.g. mNewTextStart for a delete) because that makes the
-            // merging logic more complex (e.g. merging deletes could lead to mNewTextStart being
-            // outside the bounds of the final text).
-            if (mNewText.length() > 0 && mOldText.length() == 0) {
-                mType = TYPE_INSERT;
-                mNewTextStart = dstart;
-            } else if (mNewText.length() == 0 && mOldText.length() > 0) {
-                mType = TYPE_DELETE;
-                mOldTextStart = dstart;
-            } else {
-                mType = TYPE_REPLACE;
-                mOldTextStart = mNewTextStart = dstart;
-            }
-
-            // Store cursor data.
-            mOldCursorPos = editor.mTextView.getSelectionStart();
-            mNewCursorPos = dstart + (end - start);
+        public TextModifyOperation(UndoOwner owner) {
+            super(owner);
         }
 
-        public EditOperation(Parcel src, ClassLoader loader) {
+        public TextModifyOperation(Parcel src, ClassLoader loader) {
             super(src, loader);
-            mType = src.readInt();
-            mOldText = src.readString();
-            mOldTextStart = src.readInt();
-            mNewText = src.readString();
-            mNewTextStart = src.readInt();
-            mOldCursorPos = src.readInt();
-            mNewCursorPos = src.readInt();
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(mType);
-            dest.writeString(mOldText);
-            dest.writeInt(mOldTextStart);
-            dest.writeString(mNewText);
-            dest.writeInt(mNewTextStart);
-            dest.writeInt(mOldCursorPos);
-            dest.writeInt(mNewCursorPos);
+            mRangeStart = src.readInt();
+            mRangeEnd = src.readInt();
+            mOldText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src);
         }
 
         @Override
@@ -4345,139 +4312,62 @@
 
         @Override
         public void undo() {
-            if (DEBUG_UNDO) Log.d(TAG, "undo");
-            // Remove the new text and insert the old.
-            modifyText(mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart, mOldCursorPos);
+            swapText();
         }
 
         @Override
         public void redo() {
-            if (DEBUG_UNDO) Log.d(TAG, "redo");
-            // Remove the old text and insert the new.
-            modifyText(mOldTextStart, getOldTextEnd(), mNewText, mNewTextStart, mNewCursorPos);
+            swapText();
         }
 
-        /**
-         * Attempts to merge this existing operation with a new edit.
-         * @param edit The new edit operation.
-         * @return If the merge succeeded, returns true. Otherwise returns false and leaves this
-         * object unchanged.
-         */
-        private boolean mergeWith(EditOperation edit) {
-            switch (mType) {
-                case TYPE_INSERT:
-                    return mergeInsertWith(edit);
-                case TYPE_DELETE:
-                    return mergeDeleteWith(edit);
-                case TYPE_REPLACE:
-                    return mergeReplaceWith(edit);
-                default:
-                    return false;
-            }
-        }
-
-        private boolean mergeInsertWith(EditOperation edit) {
-            if (DEBUG_UNDO) Log.d(TAG, "mergeInsertWith " + edit);
-            // Only merge continuous insertions.
-            if (edit.mType != TYPE_INSERT) {
-                return false;
-            }
-            // Only merge insertions that are contiguous.
-            if (getNewTextEnd() != edit.mNewTextStart) {
-                return false;
-            }
-            mNewText += edit.mNewText;
-            mNewCursorPos = edit.mNewCursorPos;
-            return true;
-        }
-
-        // TODO: Support forward delete.
-        private boolean mergeDeleteWith(EditOperation edit) {
-            if (DEBUG_UNDO) Log.d(TAG, "mergeDeleteWith " + edit);
-            // Only merge continuous deletes.
-            if (edit.mType != TYPE_DELETE) {
-                return false;
-            }
-            // Only merge deletions that are contiguous.
-            if (mOldTextStart != edit.getOldTextEnd()) {
-                return false;
-            }
-            mOldTextStart = edit.mOldTextStart;
-            mOldText = edit.mOldText + mOldText;
-            mNewCursorPos = edit.mNewCursorPos;
-            return true;
-        }
-
-        private boolean mergeReplaceWith(EditOperation edit) {
-            if (DEBUG_UNDO) Log.d(TAG, "mergeReplaceWith " + edit);
-            // Replacements can merge only with adjacent inserts and adjacent replacements.
-            if (edit.mType == TYPE_DELETE ||
-                    getNewTextEnd() != edit.mOldTextStart ||
-                    edit.mOldTextStart != edit.mNewTextStart) {
-                return false;
-            }
-            mOldText += edit.mOldText;
-            mNewText += edit.mNewText;
-            mNewCursorPos = edit.mNewCursorPos;
-            return true;
-        }
-
-        private int getNewTextEnd() {
-            return mNewTextStart + mNewText.length();
-        }
-
-        private int getOldTextEnd() {
-            return mOldTextStart + mOldText.length();
-        }
-
-        private void modifyText(int deleteFrom, int deleteTo, CharSequence newText,
-                int newTextInsertAt, int newCursorPos) {
+        private void swapText() {
+            // Both undo and redo involves swapping the contents of the range
+            // in the text view with our local text.
             Editor editor = getOwnerData();
-            Editable text = (Editable) editor.mTextView.getText();
-            // Apply the edit if it is still valid.
-            if (isValidRange(text, deleteFrom, deleteTo) &&
-                    newTextInsertAt <= text.length() - (deleteTo - deleteFrom)) {
-                if (deleteFrom != deleteTo) {
-                    text.delete(deleteFrom, deleteTo);
-                }
-                if (newText.length() != 0) {
-                    text.insert(newTextInsertAt, newText);
-                }
+            Editable editable = (Editable)editor.mTextView.getText();
+            CharSequence curText;
+            if (mRangeStart >= mRangeEnd) {
+                curText = null;
+            } else {
+                curText = editable.subSequence(mRangeStart, mRangeEnd);
             }
-            // Restore the cursor position.
-            // TODO: Select all the text that was undone.
-            if (newCursorPos <= text.length()) {
-                Selection.setSelection(text, newCursorPos);
+            if (DEBUG_UNDO) {
+                Log.d(TAG, "Swap: range=(" + mRangeStart + "-" + mRangeEnd
+                        + "), oldText=" + mOldText);
+                Log.d(TAG, "Swap: curText=" + curText);
             }
+            if (mOldText == null) {
+                editable.delete(mRangeStart, mRangeEnd);
+                mRangeEnd = mRangeStart;
+            } else {
+                editable.replace(mRangeStart, mRangeEnd, mOldText);
+                mRangeEnd = mRangeStart + mOldText.length();
+            }
+            mOldText = curText;
         }
 
         @Override
-        public String toString() {
-            return "EditOperation: [" +
-                    "mType=" + mType + ", " +
-                    "mOldText=" + mOldText + ", " +
-                    "mOldTextStart=" + mOldTextStart + ", " +
-                    "mNewText=" + mNewText + ", " +
-                    "mNewTextStart=" + mNewTextStart + ", " +
-                    "mOldCursorPos=" + mOldCursorPos + ", " +
-                    "mNewCursorPos=" + mNewCursorPos + "]";
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mRangeStart);
+            dest.writeInt(mRangeEnd);
+            TextUtils.writeToParcel(mOldText, dest, flags);
         }
 
-        public static final Parcelable.ClassLoaderCreator<EditOperation> CREATOR
-                = new Parcelable.ClassLoaderCreator<EditOperation>() {
+        public static final Parcelable.ClassLoaderCreator<TextModifyOperation> CREATOR
+                = new Parcelable.ClassLoaderCreator<TextModifyOperation>() {
             @Override
-            public EditOperation createFromParcel(Parcel in) {
-                return new EditOperation(in, null);
+            public TextModifyOperation createFromParcel(Parcel in) {
+                return new TextModifyOperation(in, null);
             }
 
             @Override
-            public EditOperation createFromParcel(Parcel in, ClassLoader loader) {
-                return new EditOperation(in, loader);
+            public TextModifyOperation createFromParcel(Parcel in, ClassLoader loader) {
+                return new TextModifyOperation(in, loader);
             }
 
             @Override
-            public EditOperation[] newArray(int size) {
-                return new EditOperation[size];
+            public TextModifyOperation[] newArray(int size) {
+                return new TextModifyOperation[size];
             }
         };
     }
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 03878fc..9f98965 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1235,24 +1235,6 @@
         }
     }
 
-    private void setDrawableTint(int id, ColorStateList tint, Mode tintMode, boolean fallback) {
-        Drawable layer = null;
-
-        // We expect a layer drawable, so try to find the target ID.
-        final Drawable d = mCurrentDrawable;
-        if (d instanceof LayerDrawable) {
-            layer = ((LayerDrawable) d).findDrawableByLayerId(id);
-        }
-
-        if (fallback && layer == null) {
-            layer = d;
-        }
-
-        layer.mutate();
-        layer.setTintList(tint);
-        layer.setTintMode(tintMode);
-    }
-
     private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
             boolean callBackToApp) {
         float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index 3068de9..25b301f 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -37,8 +37,6 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
 
 /**
  * Widget used to show an image with the standard QuickContact badge
@@ -52,6 +50,7 @@
     private QueryHandler mQueryHandler;
     private Drawable mDefaultAvatar;
     private Bundle mExtras = null;
+    private String mPrioritizedMimeType;
 
     protected String[] mExcludeMimes = null;
 
@@ -126,6 +125,15 @@
     public void setMode(int size) {
     }
 
+    /**
+     * Set which mimetype should be prioritized in the QuickContacts UI. For example, passing the
+     * value {@link Email#CONTENT_ITEM_TYPE} can cause emails to be displayed more prominently in
+     * QuickContacts.
+     */
+    public void setPrioritizedMimeType(String prioritizedMimeType) {
+        mPrioritizedMimeType = prioritizedMimeType;
+    }
+
     @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
@@ -287,7 +295,7 @@
         final Bundle extras = (mExtras == null) ? new Bundle() : mExtras;
         if (mContactUri != null) {
             QuickContact.showQuickContact(getContext(), QuickContactBadge.this, mContactUri,
-                    QuickContact.MODE_LARGE, mExcludeMimes);
+                    mExcludeMimes, mPrioritizedMimeType);
         } else if (mContactEmail != null && mQueryHandler != null) {
             extras.putString(EXTRA_URI_CONTENT, mContactEmail);
             mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP_AND_TRIGGER, extras,
@@ -370,10 +378,10 @@
             mContactUri = lookupUri;
             onContactUriChanged();
 
-            if (trigger && lookupUri != null) {
+            if (trigger && mContactUri != null) {
                 // Found contact, so trigger QuickContact
-                QuickContact.showQuickContact(getContext(), QuickContactBadge.this, lookupUri,
-                        QuickContact.MODE_LARGE, mExcludeMimes);
+                QuickContact.showQuickContact(getContext(), QuickContactBadge.this, mContactUri,
+                        mExcludeMimes, mPrioritizedMimeType);
             } else if (createUri != null) {
                 // Prompt user to add this person to contacts
                 final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, createUri);
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index dc4d932..28b4db2 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -157,6 +157,7 @@
     private boolean mIsOnInnerCircle;
 
     private int mSelectorRadius;
+    private int mSelectorStroke;
     private int mSelectorDotRadius;
     private int mCenterDotRadius;
 
@@ -377,6 +378,7 @@
         mPaintBackground.setAntiAlias(true);
 
         mSelectorRadius = res.getDimensionPixelSize(R.dimen.timepicker_selector_radius);
+        mSelectorStroke = res.getDimensionPixelSize(R.dimen.timepicker_selector_stroke);
         mSelectorDotRadius = res.getDimensionPixelSize(R.dimen.timepicker_selector_dot_radius);
         mCenterDotRadius = res.getDimensionPixelSize(R.dimen.timepicker_center_dot_radius);
 
@@ -772,6 +774,7 @@
         alpha = (int) (mAlphaSelector[index % 2][SELECTOR_LINE].getValue() * alphaMod + 0.5f);
         paint = mPaintSelector[index % 2][SELECTOR_LINE];
         paint.setColor(color);
+        paint.setStrokeWidth(mSelectorStroke);
         paint.setAlpha(getMultipliedAlpha(color, alpha));
         canvas.drawLine(mXCenter, mYCenter, pointX, pointY, paint);
     }
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index fef56b8..6166c02e 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -1358,6 +1358,7 @@
          *        {@link android.widget.RelativeLayout RelativeLayout}, such as
          *        ALIGN_WITH_PARENT_LEFT.
          * @see #addRule(int, int)
+         * @see #getRule(int)
          */
         public void addRule(int verb) {
             mRules[verb] = TRUE;
@@ -1378,6 +1379,7 @@
          *        for true or 0 for false).  For verbs that don't refer to another sibling
          *        (for example, ALIGN_WITH_PARENT_BOTTOM) just use -1.
          * @see #addRule(int)
+         * @see #getRule(int)
          */
         public void addRule(int verb, int anchor) {
             mRules[verb] = anchor;
@@ -1393,6 +1395,7 @@
          *         ALIGN_WITH_PARENT_LEFT.
          * @see #addRule(int)
          * @see #addRule(int, int)
+         * @see #getRule(int)
          */
         public void removeRule(int verb) {
             mRules[verb] = 0;
@@ -1400,6 +1403,22 @@
             mRulesChanged = true;
         }
 
+        /**
+         * Returns the layout rule associated with a specific verb.
+         *
+         * @param verb one of the verbs defined by {@link RelativeLayout}, such
+         *             as ALIGN_WITH_PARENT_LEFT
+         * @return the id of another view to use as an anchor, a boolean value
+         *         (represented as {@link RelativeLayout#TRUE} for true
+         *         or 0 for false), or -1 for verbs that don't refer to another
+         *         sibling (for example, ALIGN_WITH_PARENT_BOTTOM)
+         * @see #addRule(int)
+         * @see #addRule(int, int)
+         */
+        public int getRule(int verb) {
+            return mRules[verb];
+        }
+
         private boolean hasRelativeRules() {
             return (mInitialRules[START_OF] != 0 || mInitialRules[END_OF] != 0 ||
                     mInitialRules[ALIGN_START] != 0 || mInitialRules[ALIGN_END] != 0 ||
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index ed052af..3b88b21 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -132,19 +132,19 @@
         mPmText = amPmStrings[1];
 
         final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
-                R.layout.time_picker_holo);
+                R.layout.time_picker_material);
         final View mainView = inflater.inflate(layoutResourceId, delegator);
 
         mHeaderView = mainView.findViewById(R.id.time_header);
         mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground));
 
         // Set up hour/minute labels.
-        mHourView = (TextView) mHeaderView.findViewById(R.id.hours);
+        mHourView = (TextView) mainView.findViewById(R.id.hours);
         mHourView.setOnClickListener(mClickListener);
         mHourView.setAccessibilityDelegate(
                 new ClickActionDelegate(context, R.string.select_hours));
-        mSeparatorView = (TextView) mHeaderView.findViewById(R.id.separator);
-        mMinuteView = (TextView) mHeaderView.findViewById(R.id.minutes);
+        mSeparatorView = (TextView) mainView.findViewById(R.id.separator);
+        mMinuteView = (TextView) mainView.findViewById(R.id.minutes);
         mMinuteView.setOnClickListener(mClickListener);
         mMinuteView.setAccessibilityDelegate(
                 new ClickActionDelegate(context, R.string.select_minutes));
@@ -162,17 +162,8 @@
         mHourView.setMinWidth(computeStableWidth(mHourView, 24));
         mMinuteView.setMinWidth(computeStableWidth(mMinuteView, 60));
 
-        // TODO: This can be removed once we support themed color state lists.
-        final int headerSelectedTextColor = a.getColor(
-                R.styleable.TimePicker_headerSelectedTextColor,
-                res.getColor(R.color.timepicker_default_selector_color_material));
-        mHourView.setTextColor(ColorStateList.addFirstIfMissing(mHourView.getTextColors(),
-                R.attr.state_selected, headerSelectedTextColor));
-        mMinuteView.setTextColor(ColorStateList.addFirstIfMissing(mMinuteView.getTextColors(),
-                R.attr.state_selected, headerSelectedTextColor));
-
         // Set up AM/PM labels.
-        mAmPmLayout = mHeaderView.findViewById(R.id.ampm_layout);
+        mAmPmLayout = mainView.findViewById(R.id.ampm_layout);
         mAmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.am_label);
         mAmLabel.setText(amPmStrings[0]);
         mAmLabel.setOnClickListener(mClickListener);
@@ -304,12 +295,15 @@
 
             final RelativeLayout.LayoutParams params =
                     (RelativeLayout.LayoutParams) mAmPmLayout.getLayoutParams();
-            if (isAmPmAtStart) {
-                params.removeRule(RelativeLayout.RIGHT_OF);
-                params.addRule(RelativeLayout.LEFT_OF, mHourView.getId());
-            } else {
-                params.removeRule(RelativeLayout.LEFT_OF);
-                params.addRule(RelativeLayout.RIGHT_OF, mMinuteView.getId());
+            if (params.getRule(RelativeLayout.RIGHT_OF) != 0 ||
+                    params.getRule(RelativeLayout.LEFT_OF) != 0) {
+                if (isAmPmAtStart) {
+                    params.removeRule(RelativeLayout.RIGHT_OF);
+                    params.addRule(RelativeLayout.LEFT_OF, mHourView.getId());
+                } else {
+                    params.removeRule(RelativeLayout.LEFT_OF);
+                    params.addRule(RelativeLayout.RIGHT_OF, mMinuteView.getId());
+                }
             }
 
             mAmPmLayout.setLayoutParams(params);
@@ -613,11 +607,11 @@
     private void updateAmPmLabelStates(int amOrPm) {
         final boolean isAm = amOrPm == AM;
         mAmLabel.setChecked(isAm);
-        mAmLabel.setAlpha(isAm ? 1 : mDisabledAlpha);
+        mAmLabel.setSelected(isAm);
 
         final boolean isPm = amOrPm == PM;
         mPmLabel.setChecked(isPm);
-        mPmLabel.setAlpha(isPm ? 1 : mDisabledAlpha);
+        mPmLabel.setSelected(isPm);
     }
 
     /**
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index c5325c4..9bc2aab 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -20,8 +20,9 @@
 import android.annotation.Nullable;
 import android.app.ActionBar;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
-import android.graphics.RectF;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -104,6 +105,9 @@
     private ImageButton mNavButtonView;
     private ImageView mLogoView;
 
+    private TintInfo mOverflowTintInfo;
+    private TintInfo mNavTintInfo;
+
     private Drawable mCollapseIcon;
     private CharSequence mCollapseDescription;
     private ImageButton mCollapseButtonView;
@@ -266,6 +270,21 @@
         if (!TextUtils.isEmpty(navDesc)) {
             setNavigationContentDescription(navDesc);
         }
+
+        if (a.hasValue(R.styleable.Toolbar_overflowTint)) {
+            setOverflowTintList(a.getColorStateList(R.styleable.Toolbar_overflowTint));
+        }
+        if (a.hasValue(R.styleable.Toolbar_overflowTintMode)) {
+            setOverflowTintMode(Drawable.parseTintMode(
+                    a.getInt(R.styleable.Toolbar_overflowTintMode, -1), null));
+        }
+        if (a.hasValue(R.styleable.Toolbar_navigationTint)) {
+            setNavigationTintList(a.getColorStateList(R.styleable.Toolbar_navigationTint));
+        }
+        if (a.hasValue(R.styleable.Toolbar_navigationTintMode)) {
+            setNavigationTintMode(Drawable.parseTintMode(
+                    a.getInt(R.styleable.Toolbar_navigationTintMode, -1), null));
+        }
         a.recycle();
     }
 
@@ -806,6 +825,91 @@
     }
 
     /**
+     * Applies a tint to the icon drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     * <p>
+     * Subsequent calls to {@link #setNavigationIcon(Drawable)} will automatically mutate
+     * the drawable and apply the specified tint and tint mode.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#Toolbar_navigationTint
+     */
+    public void setNavigationTintList(ColorStateList tint) {
+        if (mNavTintInfo == null) {
+            mNavTintInfo = new TintInfo();
+        }
+        mNavTintInfo.mTintList = tint;
+        mNavTintInfo.mHasTintList = true;
+
+        applyNavigationTint();
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by {@link
+     * #setNavigationTintList(ColorStateList)} to the navigation drawable.
+     * The default mode is {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#Toolbar_navigationTintMode
+     */
+    public void setNavigationTintMode(PorterDuff.Mode tintMode) {
+        if (mNavTintInfo == null) {
+            mNavTintInfo = new TintInfo();
+        }
+        mNavTintInfo.mTintMode = tintMode;
+        mNavTintInfo.mHasTintMode = true;
+
+        applyNavigationTint();
+    }
+
+    /**
+     * Applies a tint to the overflow drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#Toolbar_overflowTint
+     */
+    public void setOverflowTintList(ColorStateList tint) {
+        if (mMenuView != null) {
+            // If the menu view is available, directly set the tint
+            mMenuView.setOverflowTintList(tint);
+        } else {
+            // Otherwise we will record the value
+            if (mOverflowTintInfo == null) {
+                mOverflowTintInfo = new TintInfo();
+            }
+            mOverflowTintInfo.mTintList = tint;
+            mOverflowTintInfo.mHasTintList = true;
+        }
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by {@link
+     * #setOverflowTintList(ColorStateList)} to the overflow drawable.
+     * The default mode is {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
+     *
+     * @attr ref android.R.styleable#Toolbar_overflowTintMode
+     */
+    public void setOverflowTintMode(PorterDuff.Mode tintMode) {
+        if (mMenuView != null) {
+            // If the menu view is available, directly set the tint mode
+            mMenuView.setOverflowTintMode(tintMode);
+        } else {
+            // Otherwise we will record the value
+            if (mOverflowTintInfo == null) {
+                mOverflowTintInfo = new TintInfo();
+            }
+            mOverflowTintInfo.mTintMode = tintMode;
+            mOverflowTintInfo.mHasTintMode = true;
+        }
+    }
+
+    /**
      * Return the Menu shown in the toolbar.
      *
      * <p>Applications that wish to populate the toolbar's menu can do so from here. To use
@@ -841,6 +945,17 @@
             lp.gravity = Gravity.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
             mMenuView.setLayoutParams(lp);
             addSystemView(mMenuView);
+
+            if (mOverflowTintInfo != null) {
+                // If we have tint info for the overflow, set it on the menu view now
+                if (mOverflowTintInfo.mHasTintList) {
+                    mMenuView.setOverflowTintList(mOverflowTintInfo.mTintList);
+                }
+                if (mOverflowTintInfo.mHasTintMode) {
+                    mMenuView.setOverflowTintMode(mOverflowTintInfo.mTintMode);
+                }
+                mOverflowTintInfo = null;
+            }
         }
     }
 
@@ -994,6 +1109,7 @@
             final LayoutParams lp = generateDefaultLayoutParams();
             lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
             mNavButtonView.setLayoutParams(lp);
+            applyNavigationTint();
         }
     }
 
@@ -1012,6 +1128,7 @@
                     collapseActionView();
                 }
             });
+            applyNavigationTint();
         }
     }
 
@@ -1763,6 +1880,30 @@
         return mPopupContext;
     }
 
+    private void applyNavigationTint() {
+        final TintInfo tintInfo = mNavTintInfo;
+        if (tintInfo != null && (tintInfo.mHasTintList || tintInfo.mHasTintMode)) {
+            if (mNavButtonView != null) {
+                if (tintInfo.mHasTintList) {
+                    mNavButtonView.setImageTintList(tintInfo.mTintList);
+                }
+                if (tintInfo.mHasTintMode) {
+                    mNavButtonView.setImageTintMode(tintInfo.mTintMode);
+                }
+            }
+
+            if (mCollapseButtonView != null) {
+                // We will use the same tint for the collapse button
+                if (tintInfo.mHasTintList) {
+                    mCollapseButtonView.setImageTintList(tintInfo.mTintList);
+                }
+                if (tintInfo.mHasTintMode) {
+                    mCollapseButtonView.setImageTintMode(tintInfo.mTintMode);
+                }
+            }
+        }
+    }
+
     /**
      * Interface responsible for receiving menu item click events if the items themselves
      * do not have individual item click listeners.
@@ -1990,4 +2131,11 @@
         public void onRestoreInstanceState(Parcelable state) {
         }
     }
+
+    private static class TintInfo {
+        ColorStateList mTintList;
+        PorterDuff.Mode mTintMode;
+        boolean mHasTintMode;
+        boolean mHasTintList;
+    }
 }
diff --git a/core/java/android/alsa/AlsaCardsParser.java b/core/java/com/android/internal/alsa/AlsaCardsParser.java
similarity index 99%
rename from core/java/android/alsa/AlsaCardsParser.java
rename to core/java/com/android/internal/alsa/AlsaCardsParser.java
index 5e88bca..5c0a888 100644
--- a/core/java/android/alsa/AlsaCardsParser.java
+++ b/core/java/com/android/internal/alsa/AlsaCardsParser.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.alsa;
+package com.android.internal.alsa;
 
 import android.util.Slog;
 import java.io.BufferedReader;
diff --git a/core/java/android/alsa/AlsaDevicesParser.java b/core/java/com/android/internal/alsa/AlsaDevicesParser.java
similarity index 99%
rename from core/java/android/alsa/AlsaDevicesParser.java
rename to core/java/com/android/internal/alsa/AlsaDevicesParser.java
index b140d3d..81b7943 100644
--- a/core/java/android/alsa/AlsaDevicesParser.java
+++ b/core/java/com/android/internal/alsa/AlsaDevicesParser.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.alsa;
+package com.android.internal.alsa;
 
 import android.util.Slog;
 import java.io.BufferedReader;
diff --git a/core/java/android/alsa/LineTokenizer.java b/core/java/com/android/internal/alsa/LineTokenizer.java
similarity index 97%
rename from core/java/android/alsa/LineTokenizer.java
rename to core/java/com/android/internal/alsa/LineTokenizer.java
index 78c91b5..43047a9 100644
--- a/core/java/android/alsa/LineTokenizer.java
+++ b/core/java/com/android/internal/alsa/LineTokenizer.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.alsa;
+package com.android.internal.alsa;
 
 /**
  * @hide
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 20d209f..9dabb4e 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -20,6 +20,7 @@
 
 import com.android.internal.R;
 
+import android.annotation.Nullable;
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -38,7 +39,7 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewParent;
-import android.view.ViewTreeObserver;
+import android.view.ViewStub;
 import android.view.Window;
 import android.view.WindowInsets;
 import android.view.WindowManager;
@@ -450,27 +451,107 @@
         }
     }
 
+    /**
+     * Resolves whether a custom or default panel should be used. Removes the
+     * default panel if a custom panel should be used. If the resolved panel is
+     * a view stub, inflates before returning.
+     *
+     * @param customPanel the custom panel
+     * @param defaultPanel the default panel
+     * @return the panel to use
+     */
+    @Nullable
+    private ViewGroup resolvePanel(@Nullable View customPanel, @Nullable View defaultPanel) {
+        if (customPanel == null) {
+            // Inflate the default panel, if needed.
+            if (defaultPanel instanceof ViewStub) {
+                defaultPanel = ((ViewStub) defaultPanel).inflate();
+            }
+
+            return (ViewGroup) defaultPanel;
+        }
+
+        // Remove the default panel entirely.
+        if (defaultPanel != null) {
+            final ViewParent parent = defaultPanel.getParent();
+            if (parent instanceof ViewGroup) {
+                ((ViewGroup) parent).removeView(defaultPanel);
+            }
+        }
+
+        // Inflate the custom panel, if needed.
+        if (customPanel instanceof ViewStub) {
+            customPanel = ((ViewStub) customPanel).inflate();
+        }
+
+        return (ViewGroup) customPanel;
+    }
+
     private void setupView() {
-        final ViewGroup contentPanel = (ViewGroup) mWindow.findViewById(R.id.contentPanel);
+        final View parentPanel = mWindow.findViewById(R.id.parentPanel);
+        final View defaultTopPanel = parentPanel.findViewById(R.id.topPanel);
+        final View defaultContentPanel = parentPanel.findViewById(R.id.contentPanel);
+        final View defaultButtonPanel = parentPanel.findViewById(R.id.buttonPanel);
+
+        // Install custom content before setting up the title or buttons so
+        // that we can handle panel overrides.
+        final ViewGroup customPanel = (ViewGroup) parentPanel.findViewById(R.id.customPanel);
+        setupCustomContent(customPanel);
+
+        final View customTopPanel = customPanel.findViewById(R.id.topPanel);
+        final View customContentPanel = customPanel.findViewById(R.id.contentPanel);
+        final View customButtonPanel = customPanel.findViewById(R.id.buttonPanel);
+
+        // Resolve the correct panels and remove the defaults, if needed.
+        final ViewGroup topPanel = resolvePanel(customTopPanel, defaultTopPanel);
+        final ViewGroup contentPanel = resolvePanel(customContentPanel, defaultContentPanel);
+        final ViewGroup buttonPanel = resolvePanel(customButtonPanel, defaultButtonPanel);
+
         setupContent(contentPanel);
-        final boolean hasButtons = setupButtons();
+        setupButtons(buttonPanel);
+        setupTitle(topPanel);
 
-        final ViewGroup topPanel = (ViewGroup) mWindow.findViewById(R.id.topPanel);
-        final TypedArray a = mContext.obtainStyledAttributes(
-                null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
-        final boolean hasTitle = setupTitle(topPanel);
+        final boolean hasCustomPanel = customPanel != null
+                && customPanel.getVisibility() != View.GONE;
+        final boolean hasTopPanel = topPanel != null
+                && topPanel.getVisibility() != View.GONE;
+        final boolean hasButtonPanel = buttonPanel != null
+                && buttonPanel.getVisibility() != View.GONE;
 
-        final View buttonPanel = mWindow.findViewById(R.id.buttonPanel);
-        if (!hasButtons) {
-            buttonPanel.setVisibility(View.GONE);
-            final View spacer = mWindow.findViewById(R.id.textSpacerNoButtons);
-            if (spacer != null) {
-                spacer.setVisibility(View.VISIBLE);
+        // Only display the text spacer if we don't have buttons.
+        if (!hasButtonPanel) {
+            if (contentPanel != null) {
+                final View spacer = contentPanel.findViewById(R.id.textSpacerNoButtons);
+                if (spacer != null) {
+                    spacer.setVisibility(View.VISIBLE);
+                }
             }
             mWindow.setCloseOnTouchOutsideIfNotSet(true);
         }
 
-        final FrameLayout customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel);
+        // Only display the divider if we have a title and a custom view or a
+        // message.
+        if (hasTopPanel) {
+            final View divider;
+            if (mMessage != null || hasCustomPanel || mListView != null) {
+                divider = topPanel.findViewById(R.id.titleDivider);
+            } else {
+                divider = topPanel.findViewById(R.id.titleDividerTop);
+            }
+
+            if (divider != null) {
+                divider.setVisibility(View.VISIBLE);
+            }
+        }
+
+        final TypedArray a = mContext.obtainStyledAttributes(
+                null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
+        setBackground(a, topPanel, contentPanel, customPanel, buttonPanel,
+                hasTopPanel, hasCustomPanel, hasButtonPanel);
+        a.recycle();
+    }
+
+    private void setupCustomContent(ViewGroup customPanel) {
         final View customView;
         if (mView != null) {
             customView = mView;
@@ -502,30 +583,9 @@
         } else {
             customPanel.setVisibility(View.GONE);
         }
-
-        // Only display the divider if we have a title and a custom view or a
-        // message.
-        if (hasTitle) {
-            final View divider;
-            if (mMessage != null || customView != null || mListView != null) {
-                divider = mWindow.findViewById(R.id.titleDivider);
-            } else {
-                divider = mWindow.findViewById(R.id.titleDividerTop);
-            }
-
-            if (divider != null) {
-                divider.setVisibility(View.VISIBLE);
-            }
-        }
-
-        setBackground(a, topPanel, contentPanel, customPanel, buttonPanel, hasTitle, hasCustomView,
-                hasButtons);
-        a.recycle();
     }
 
-    private boolean setupTitle(ViewGroup topPanel) {
-        boolean hasTitle = true;
-
+    private void setupTitle(ViewGroup topPanel) {
         if (mCustomTitleView != null) {
             // Add the custom title view directly to the topPanel layout
             LayoutParams lp = new LayoutParams(
@@ -567,18 +627,16 @@
                 titleTemplate.setVisibility(View.GONE);
                 mIconView.setVisibility(View.GONE);
                 topPanel.setVisibility(View.GONE);
-                hasTitle = false;
             }
         }
-        return hasTitle;
     }
 
     private void setupContent(ViewGroup contentPanel) {
-        mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView);
+        mScrollView = (ScrollView) contentPanel.findViewById(R.id.scrollView);
         mScrollView.setFocusable(false);
 
         // Special case for users that only want to display a String
-        mMessageView = (TextView) mWindow.findViewById(R.id.message);
+        mMessageView = (TextView) contentPanel.findViewById(R.id.message);
         if (mMessageView == null) {
             return;
         }
@@ -601,8 +659,8 @@
         }
 
         // Set up scroll indicators (if present).
-        final View indicatorUp = mWindow.findViewById(R.id.scrollIndicatorUp);
-        final View indicatorDown = mWindow.findViewById(R.id.scrollIndicatorDown);
+        final View indicatorUp = contentPanel.findViewById(R.id.scrollIndicatorUp);
+        final View indicatorDown = contentPanel.findViewById(R.id.scrollIndicatorDown);
         if (indicatorUp != null || indicatorDown != null) {
             if (mMessage != null) {
                 // We're just showing the ScrollView, set up listener.
@@ -663,12 +721,12 @@
         }
     }
 
-    private boolean setupButtons() {
+    private void setupButtons(ViewGroup buttonPanel) {
         int BIT_BUTTON_POSITIVE = 1;
         int BIT_BUTTON_NEGATIVE = 2;
         int BIT_BUTTON_NEUTRAL = 4;
         int whichButtons = 0;
-        mButtonPositive = (Button) mWindow.findViewById(R.id.button1);
+        mButtonPositive = (Button) buttonPanel.findViewById(R.id.button1);
         mButtonPositive.setOnClickListener(mButtonHandler);
 
         if (TextUtils.isEmpty(mButtonPositiveText)) {
@@ -679,7 +737,7 @@
             whichButtons = whichButtons | BIT_BUTTON_POSITIVE;
         }
 
-        mButtonNegative = (Button) mWindow.findViewById(R.id.button2);
+        mButtonNegative = (Button) buttonPanel.findViewById(R.id.button2);
         mButtonNegative.setOnClickListener(mButtonHandler);
 
         if (TextUtils.isEmpty(mButtonNegativeText)) {
@@ -691,7 +749,7 @@
             whichButtons = whichButtons | BIT_BUTTON_NEGATIVE;
         }
 
-        mButtonNeutral = (Button) mWindow.findViewById(R.id.button3);
+        mButtonNeutral = (Button) buttonPanel.findViewById(R.id.button3);
         mButtonNeutral.setOnClickListener(mButtonHandler);
 
         if (TextUtils.isEmpty(mButtonNeutralText)) {
@@ -717,7 +775,10 @@
             }
         }
 
-        return whichButtons != 0;
+        final boolean hasButtons = whichButtons != 0;
+        if (!hasButtons) {
+            buttonPanel.setVisibility(View.GONE);
+        }
     }
 
     private void centerButton(Button button) {
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/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
index ed676bb..00af401 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItem.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -18,6 +18,8 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.view.ActionProvider;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -42,6 +44,7 @@
     
     private Drawable mIconDrawable;
     private int mIconResId = NO_ICON;
+    private TintInfo mIconTintInfo;
     
     private Context mContext;
     
@@ -158,12 +161,14 @@
     public MenuItem setIcon(Drawable icon) {
         mIconDrawable = icon;
         mIconResId = NO_ICON;
+        applyIconTint();
         return this;
     }
 
     public MenuItem setIcon(int iconRes) {
         mIconResId = iconRes;
         mIconDrawable = mContext.getDrawable(iconRes);
+        applyIconTint();
         return this;
     }
 
@@ -274,4 +279,48 @@
         // No need to save the listener; ActionMenuItem does not support collapsing items.
         return this;
     }
+
+    @Override
+    public MenuItem setIconTintList(ColorStateList tintList) {
+        if (mIconTintInfo == null) {
+            mIconTintInfo = new TintInfo();
+        }
+        mIconTintInfo.mTintList = tintList;
+        mIconTintInfo.mHasTintList = true;
+        applyIconTint();
+        return this;
+    }
+
+    @Override
+    public MenuItem setIconTintMode(PorterDuff.Mode tintMode) {
+        if (mIconTintInfo == null) {
+            mIconTintInfo = new TintInfo();
+        }
+        mIconTintInfo.mTintMode = tintMode;
+        mIconTintInfo.mHasTintMode = true;
+        applyIconTint();
+        return this;
+    }
+
+    private void applyIconTint() {
+        final TintInfo tintInfo = mIconTintInfo;
+        if (mIconDrawable != null && tintInfo != null) {
+            if (tintInfo.mHasTintList || tintInfo.mHasTintMode) {
+                mIconDrawable = mIconDrawable.mutate();
+                if (tintInfo.mHasTintList) {
+                    mIconDrawable.setTintList(tintInfo.mTintList);
+                }
+                if (tintInfo.mHasTintMode) {
+                    mIconDrawable.setTintMode(tintInfo.mTintMode);
+                }
+            }
+        }
+    }
+
+    private static class TintInfo {
+        ColorStateList mTintList;
+        PorterDuff.Mode mTintMode;
+        boolean mHasTintMode;
+        boolean mHasTintList;
+    }
 }
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 3b1f20d..ef4e546 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -21,6 +21,8 @@
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.util.Log;
 import android.view.ActionProvider;
@@ -60,6 +62,11 @@
      * needed).
      */ 
     private int mIconResId = NO_ICON;
+
+    /**
+     * Tint info for the icon
+     */
+    private TintInfo mIconTintInfo;
     
     /** The menu to which this item belongs */
     private MenuBuilder mMenu;
@@ -385,10 +392,10 @@
         }
 
         if (mIconResId != NO_ICON) {
-            Drawable icon =  mMenu.getContext().getDrawable(mIconResId);
+            mIconDrawable = mMenu.getContext().getDrawable(mIconResId);
             mIconResId = NO_ICON;
-            mIconDrawable = icon;
-            return icon;
+            applyIconTint();
+            return mIconDrawable;
         }
         
         return null;
@@ -397,6 +404,7 @@
     public MenuItem setIcon(Drawable icon) {
         mIconResId = NO_ICON;
         mIconDrawable = icon;
+        applyIconTint();
         mMenu.onItemsChanged(false);
         
         return this;
@@ -670,4 +678,48 @@
     public boolean isActionViewExpanded() {
         return mIsActionViewExpanded;
     }
+
+    @Override
+    public MenuItem setIconTintList(ColorStateList tintList) {
+        if (mIconTintInfo == null) {
+            mIconTintInfo = new TintInfo();
+        }
+        mIconTintInfo.mTintList = tintList;
+        mIconTintInfo.mHasTintList = true;
+        applyIconTint();
+        return this;
+    }
+
+    @Override
+    public MenuItem setIconTintMode(PorterDuff.Mode tintMode) {
+        if (mIconTintInfo == null) {
+            mIconTintInfo = new TintInfo();
+        }
+        mIconTintInfo.mTintMode = tintMode;
+        mIconTintInfo.mHasTintMode = true;
+        applyIconTint();
+        return this;
+    }
+
+    private void applyIconTint() {
+        final TintInfo tintInfo = mIconTintInfo;
+        if (mIconDrawable != null && tintInfo != null) {
+            if (tintInfo.mHasTintList || tintInfo.mHasTintMode) {
+                mIconDrawable = mIconDrawable.mutate();
+                if (tintInfo.mHasTintList) {
+                    mIconDrawable.setTintList(tintInfo.mTintList);
+                }
+                if (tintInfo.mHasTintMode) {
+                    mIconDrawable.setTintMode(tintInfo.mTintMode);
+                }
+            }
+        }
+    }
+
+    private static class TintInfo {
+        ColorStateList mTintList;
+        PorterDuff.Mode mTintMode;
+        boolean mHasTintMode;
+        boolean mHasTintList;
+    }
 }
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_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index 7497d8b..87896df 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -52,12 +52,12 @@
  * Convert from RGB 888 to Y'CbCr using the conversion specified in JFIF v1.02
  */
 static void rgbToYuv420(uint8_t* rgbBuf, size_t width, size_t height, uint8_t* yPlane,
-        uint8_t* uPlane, uint8_t* vPlane, size_t chromaStep, size_t yStride, size_t chromaStride) {
+        uint8_t* crPlane, uint8_t* cbPlane, size_t chromaStep, size_t yStride, size_t chromaStride) {
     uint8_t R, G, B;
     size_t index = 0;
     for (size_t j = 0; j < height; j++) {
-        uint8_t* u = uPlane;
-        uint8_t* v = vPlane;
+        uint8_t* cr = crPlane;
+        uint8_t* cb = cbPlane;
         uint8_t* y = yPlane;
         bool jEven = (j & 1) == 0;
         for (size_t i = 0; i < width; i++) {
@@ -66,18 +66,18 @@
             B = rgbBuf[index++];
             *y++ = (77 * R + 150 * G +  29 * B) >> 8;
             if (jEven && (i & 1) == 0) {
-                *v = (( -43 * R - 85 * G + 128 * B) >> 8) + 128;
-                *u = (( 128 * R - 107 * G - 21 * B) >> 8) + 128;
-                u += chromaStep;
-                v += chromaStep;
+                *cb = (( -43 * R - 85 * G + 128 * B) >> 8) + 128;
+                *cr = (( 128 * R - 107 * G - 21 * B) >> 8) + 128;
+                cr += chromaStep;
+                cb += chromaStep;
             }
             // Skip alpha
             index++;
         }
         yPlane += yStride;
         if (jEven) {
-            uPlane += chromaStride;
-            vPlane += chromaStride;
+            crPlane += chromaStride;
+            cbPlane += chromaStride;
         }
     }
 }
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 6c95b8a..5cb8b2e 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -188,6 +188,10 @@
             break;
         }
 
+        if (log_msg.id() != LOG_ID_EVENTS) {
+            continue;
+        }
+
         int32_t tag = * (int32_t *) log_msg.msg();
 
         int found = 0;
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 72cfd5b..0bee7ae 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -47,12 +47,6 @@
 } gRectClassInfo;
 
 // ----------------------------------------------------------------------------
-// Defines
-// ----------------------------------------------------------------------------
-
-static const bool kDebugRenderer = false;
-
-// ----------------------------------------------------------------------------
 // Setup
 // ----------------------------------------------------------------------------
 
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 13c373f..a8355c2 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -150,7 +150,7 @@
     switch (screenshot->getFormat()) {
         case PIXEL_FORMAT_RGBX_8888: {
             screenshotInfo.fColorType = kRGBA_8888_SkColorType;
-            screenshotInfo.fAlphaType = kIgnore_SkAlphaType;
+            screenshotInfo.fAlphaType = kOpaque_SkAlphaType;
             break;
         }
         case PIXEL_FORMAT_RGBA_8888: {
@@ -160,7 +160,7 @@
         }
         case PIXEL_FORMAT_RGB_565: {
             screenshotInfo.fColorType = kRGB_565_SkColorType;
-            screenshotInfo.fAlphaType = kIgnore_SkAlphaType;
+            screenshotInfo.fAlphaType = kOpaque_SkAlphaType;
             break;
         }
         default: {
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 011c326..c2bd0b3c4 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -88,12 +88,15 @@
         case WINDOW_FORMAT_RGBX_8888:
             info.fColorType = kN32_SkColorType;
             info.fAlphaType = kOpaque_SkAlphaType;
+            break;
         case WINDOW_FORMAT_RGB_565:
             info.fColorType = kRGB_565_SkColorType;
             info.fAlphaType = kOpaque_SkAlphaType;
+            break;
         default:
             info.fColorType = kUnknown_SkColorType;
-            info.fAlphaType = kIgnore_SkAlphaType;
+            // switch to kUnknown_SkAlphaType when its in skia
+            info.fAlphaType = kOpaque_SkAlphaType;
             break;
     }
     return info;
diff --git a/core/res/res/color/date_picker_calendar_holo_dark.xml b/core/res/res/color/date_picker_calendar_holo_dark.xml
deleted file mode 100644
index 6749ea1..0000000
--- a/core/res/res/color/date_picker_calendar_holo_dark.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_enabled="false"
-          android:color="@color/datepicker_default_disabled_text_color_holo_dark" />
-    <item android:state_activated="true"
-          android:color="@color/holo_blue_light" />
-    <item android:color="@color/datepicker_default_normal_text_color_holo_dark" />
-
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/date_picker_calendar_holo_light.xml b/core/res/res/color/date_picker_calendar_holo_light.xml
deleted file mode 100644
index 0aa116a..0000000
--- a/core/res/res/color/date_picker_calendar_holo_light.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_enabled="false"
-        android:color="@color/datepicker_default_disabled_text_color_holo_light" />
-    <item android:state_activated="true"
-        android:color="@color/holo_blue_light" />
-    <item android:color="@color/datepicker_default_normal_text_color_holo_light" />
-
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/date_picker_header_text_material.xml b/core/res/res/color/date_picker_header_text_material.xml
new file mode 100644
index 0000000..cda894b
--- /dev/null
+++ b/core/res/res/color/date_picker_header_text_material.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:state_selected="true"
+        android:color="?attr/textColorPrimaryInverse" />
+    <item
+        android:color="?attr/textColorSecondaryInverse" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/color/date_picker_selector_holo_dark.xml b/core/res/res/color/date_picker_selector_holo_dark.xml
deleted file mode 100644
index 9e5a5bd..0000000
--- a/core/res/res/color/date_picker_selector_holo_dark.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_pressed="true"
-          android:color="@color/datepicker_default_pressed_text_color_holo_dark"/>
-    <item android:state_pressed="false" android:state_selected="true"
-          android:color="@color/datepicker_default_selected_text_color_holo_dark"/>
-    <item android:state_pressed="false" android:state_selected="false"
-          android:color="@color/datepicker_default_normal_text_color_holo_dark"/>
-
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/date_picker_selector_holo_light.xml b/core/res/res/color/date_picker_selector_holo_light.xml
deleted file mode 100644
index bf8667c..0000000
--- a/core/res/res/color/date_picker_selector_holo_light.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_pressed="true"
-          android:color="@color/datepicker_default_pressed_text_color_holo_light"/>
-    <item android:state_pressed="false" android:state_selected="true"
-          android:color="@color/datepicker_default_selected_text_color_holo_light"/>
-    <item android:state_pressed="false" android:state_selected="false"
-          android:color="@color/datepicker_default_normal_text_color_holo_light"/>
-
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/date_picker_year_selector_holo_dark.xml b/core/res/res/color/date_picker_year_selector_holo_dark.xml
deleted file mode 100644
index ce519b2..0000000
--- a/core/res/res/color/date_picker_year_selector_holo_dark.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_pressed="true"
-          android:color="@color/datepicker_default_pressed_text_color_holo_dark"/>
-    <item android:state_pressed="false" android:state_selected="false"
-          android:color="@color/datepicker_default_normal_text_color_holo_dark"/>
-
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/date_picker_year_selector_holo_light.xml b/core/res/res/color/date_picker_year_selector_holo_light.xml
deleted file mode 100644
index c228711..0000000
--- a/core/res/res/color/date_picker_year_selector_holo_light.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_pressed="true"
-          android:color="@color/datepicker_default_pressed_text_color_holo_light"/>
-    <item android:state_pressed="false" android:state_selected="false"
-          android:color="@color/datepicker_default_normal_text_color_holo_light"/>
-
-</selector>
\ No newline at end of file
diff --git a/core/res/res/color/time_picker_header_text_material.xml b/core/res/res/color/time_picker_header_text_material.xml
new file mode 100644
index 0000000..cda894b
--- /dev/null
+++ b/core/res/res/color/time_picker_header_text_material.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:state_selected="true"
+        android:color="?attr/textColorPrimaryInverse" />
+    <item
+        android:color="?attr/textColorSecondaryInverse" />
+</selector>
\ No newline at end of file
diff --git a/core/res/res/layout-land/time_picker_holo.xml b/core/res/res/layout-land/time_picker_holo.xml
deleted file mode 100644
index f6923ee..0000000
--- a/core/res/res/layout-land/time_picker_holo.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2013, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="horizontal">
-    <FrameLayout
-        android:layout_width="0dp"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:minWidth="@dimen/timepicker_left_side_width"
-        android:orientation="vertical">
-        <include
-            layout="@layout/time_header_label"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_gravity="center" />
-    </FrameLayout>
-    <android.widget.RadialTimePickerView
-        android:id="@+id/radial_picker"
-        android:layout_width="@dimen/timepicker_radial_picker_dimen"
-        android:layout_height="match_parent"
-        android:layout_gravity="center" />
-</LinearLayout>
diff --git a/core/res/res/layout-land/time_picker_material.xml b/core/res/res/layout-land/time_picker_material.xml
new file mode 100644
index 0000000..1b85e8f
--- /dev/null
+++ b/core/res/res/layout-land/time_picker_material.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+            xmlns:tools="http://schemas.android.com/tools"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+    <View
+        android:id="@+id/time_header"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_column="0"
+        android:layout_row="0"
+        android:layout_rowSpan="3"
+        android:layout_gravity="center|fill"
+        tools:background="@color/accent_material_light" />
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_column="0"
+        android:layout_row="1"
+        android:layout_gravity="center|fill"
+        android:paddingStart="?attr/dialogPreferredPadding"
+        android:paddingEnd="?attr/dialogPreferredPadding">
+
+        <LinearLayout
+            android:id="@+id/time_layout"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:layout_centerInParent="true"
+            android:paddingTop="@dimen/timepicker_radial_picker_top_margin">
+
+            <!-- The hour should always be to the left of the separator,
+                 regardless of the current locale's layout direction. -->
+            <TextView
+                android:id="@+id/hours"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:ellipsize="none"
+                android:gravity="right"
+                tools:text="23"
+                tools:textSize="@dimen/timepicker_time_label_size"
+                tools:textColor="@color/white" />
+
+            <TextView
+                android:id="@+id/separator"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:importantForAccessibility="no"
+                tools:text=":"
+                tools:textSize="@dimen/timepicker_time_label_size"
+                tools:textColor="@color/white" />
+
+            <!-- The minutes should always be to the right of the separator,
+                 regardless of the current locale's layout direction. -->
+            <TextView
+                android:id="@+id/minutes"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:ellipsize="none"
+                android:gravity="left"
+                tools:text="59"
+                tools:textSize="@dimen/timepicker_time_label_size"
+                tools:textColor="@color/white" />
+        </LinearLayout>
+
+        <!-- The layout alignment of this view will switch between toRightOf
+             @id/minutes and toLeftOf @id/hours depending on the locale. -->
+        <LinearLayout
+            android:id="@+id/ampm_layout"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@+id/time_layout"
+            android:layout_centerHorizontal="true"
+            android:orientation="vertical">
+
+            <CheckedTextView
+                android:id="@+id/am_label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
+                android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
+                android:paddingTop="@dimen/timepicker_am_top_padding"
+                android:lines="1"
+                android:ellipsize="none"
+                android:includeFontPadding="false"
+                tools:text="AM"
+                tools:textSize="@dimen/timepicker_ampm_label_size"
+                tools:textColor="@color/white" />
+
+            <CheckedTextView
+                android:id="@+id/pm_label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
+                android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
+                android:paddingTop="@dimen/timepicker_pm_top_padding"
+                android:lines="1"
+                android:ellipsize="none"
+                android:includeFontPadding="false"
+                tools:text="PM"
+                tools:textSize="@dimen/timepicker_ampm_label_size"
+                tools:textColor="@color/white" />
+        </LinearLayout>
+    </RelativeLayout>
+
+    <ViewStub
+        android:id="@id/topPanel"
+        android:layout="@layout/alert_dialog_title_material"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_column="1"
+        android:layout_row="0"
+        android:layout_gravity="top|fill_horizontal" />
+
+    <android.widget.RadialTimePickerView
+        android:id="@+id/radial_picker"
+        android:layout_width="@dimen/timepicker_radial_picker_dimen"
+        android:layout_height="@dimen/timepicker_radial_picker_dimen"
+        android:layout_column="1"
+        android:layout_row="1"
+        android:layout_rowWeight="1"
+        android:layout_gravity="center|fill"
+        android:layout_marginTop="@dimen/timepicker_radial_picker_top_margin"
+        android:layout_marginStart="@dimen/timepicker_radial_picker_horizontal_margin"
+        android:layout_marginEnd="@dimen/timepicker_radial_picker_horizontal_margin" />
+
+    <ViewStub
+        android:id="@id/buttonPanel"
+        android:layout="@layout/alert_dialog_button_bar_material"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_column="1"
+        android:layout_row="2"
+        android:layout_gravity="bottom|fill_horizontal" />
+</GridLayout>
diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml
index c8735b1..bf1e383 100644
--- a/core/res/res/layout/alert_dialog_material.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -22,34 +22,7 @@
     android:layout_height="wrap_content"
     android:orientation="vertical">
 
-    <LinearLayout android:id="@+id/topPanel"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical">
-        <LinearLayout android:id="@+id/title_template"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:gravity="center_vertical|start"
-            android:paddingStart="?attr/dialogPreferredPadding"
-            android:paddingEnd="?attr/dialogPreferredPadding"
-            android:paddingTop="@dimen/dialog_padding_top_material">
-            <ImageView android:id="@+id/icon"
-                android:layout_width="32dip"
-                android:layout_height="32dip"
-                android:layout_marginEnd="8dip"
-                android:scaleType="fitCenter"
-                android:src="@null" />
-            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
-                style="?attr/windowTitleStyle"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textAlignment="viewStart" />
-        </LinearLayout>
-        <!-- If the client uses a customTitle, it will be added here. -->
-    </LinearLayout>
+    <include layout="@layout/alert_dialog_title_material" />
 
     <FrameLayout android:id="@+id/contentPanel"
         android:layout_width="match_parent"
diff --git a/core/res/res/layout/alert_dialog_title_material.xml b/core/res/res/layout/alert_dialog_title_material.xml
new file mode 100644
index 0000000..f61b90b
--- /dev/null
+++ b/core/res/res/layout/alert_dialog_title_material.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/topPanel"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:orientation="vertical">
+
+    <LinearLayout
+        android:id="@+id/title_template"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:gravity="center_vertical|start"
+        android:paddingStart="?attr/dialogPreferredPadding"
+        android:paddingEnd="?attr/dialogPreferredPadding"
+        android:paddingTop="@dimen/dialog_padding_top_material">
+
+        <ImageView
+            android:id="@+id/icon"
+            android:layout_width="32dip"
+            android:layout_height="32dip"
+            android:layout_marginEnd="8dip"
+            android:scaleType="fitCenter"
+            android:src="@null" />
+
+        <com.android.internal.widget.DialogTitle
+            android:id="@+id/alertTitle"
+            style="?attr/windowTitleStyle"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textAlignment="viewStart" />
+    </LinearLayout>
+
+    <!-- If the client uses a customTitle, it will be added here. -->
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/time_header_label.xml b/core/res/res/layout/time_picker_header_material.xml
similarity index 68%
rename from core/res/res/layout/time_header_label.xml
rename to core/res/res/layout/time_picker_header_material.xml
index 46e7c54..0ef404d 100644
--- a/core/res/res/layout/time_header_label.xml
+++ b/core/res/res/layout/time_picker_header_material.xml
@@ -16,12 +16,13 @@
   -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/time_header"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:gravity="center"
-    android:orientation="horizontal"
-    android:padding="@dimen/timepicker_separator_padding">
+                xmlns:tools="http://schemas.android.com/tools"
+                android:id="@+id/time_header"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:orientation="horizontal"
+                android:padding="@dimen/timepicker_separator_padding"
+                tools:background="@color/accent_material_light">
 
     <!-- The hour should always be to the left of the separator,
          regardless of the current locale's layout direction. -->
@@ -31,7 +32,12 @@
         android:layout_height="wrap_content"
         android:layout_toLeftOf="@+id/separator"
         android:layout_alignBaseline="@+id/separator"
-        android:gravity="right" />
+        android:singleLine="true"
+        android:ellipsize="none"
+        android:gravity="right"
+        tools:text="23"
+        tools:textSize="@dimen/timepicker_time_label_size"
+        tools:textColor="@color/white" />
 
     <TextView
         android:id="@+id/separator"
@@ -40,7 +46,10 @@
         android:layout_marginLeft="@dimen/timepicker_separator_padding"
         android:layout_marginRight="@dimen/timepicker_separator_padding"
         android:layout_centerInParent="true"
-        android:importantForAccessibility="no" />
+        android:importantForAccessibility="no"
+        tools:text=":"
+        tools:textSize="@dimen/timepicker_time_label_size"
+        tools:textColor="@color/white" />
 
     <!-- The minutes should always be to the left of the separator,
          regardless of the current locale's layout direction. -->
@@ -50,7 +59,12 @@
         android:layout_height="wrap_content"
         android:layout_toRightOf="@+id/separator"
         android:layout_alignBaseline="@+id/separator"
-        android:gravity="left" />
+        android:singleLine="true"
+        android:ellipsize="none"
+        android:gravity="left"
+        tools:text="59"
+        tools:textSize="@dimen/timepicker_time_label_size"
+        tools:textColor="@color/white" />
 
     <!-- The layout alignment of this view will switch between toRightOf
          @id/minutes and toLeftOf @id/hours depending on the locale. -->
@@ -68,9 +82,12 @@
             android:layout_height="wrap_content"
             android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
             android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
-            android:paddingTop="@dimen/timepicker_ampm_vertical_padding"
+            android:paddingTop="@dimen/timepicker_am_top_padding"
             android:lines="1"
-            android:ellipsize="none" />
+            android:ellipsize="none"
+            tools:text="AM"
+            tools:textSize="@dimen/timepicker_ampm_label_size"
+            tools:textColor="@color/white" />
         <CheckedTextView
             android:id="@+id/pm_label"
             android:layout_width="wrap_content"
@@ -79,6 +96,9 @@
             android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
             android:paddingTop="@dimen/timepicker_pm_top_padding"
             android:lines="1"
-            android:ellipsize="none" />
+            android:ellipsize="none"
+            tools:text="PM"
+            tools:textSize="@dimen/timepicker_ampm_label_size"
+            tools:textColor="@color/white" />
     </LinearLayout>
 </RelativeLayout>
diff --git a/core/res/res/layout/time_picker_legacy_holo.xml b/core/res/res/layout/time_picker_legacy_material.xml
similarity index 100%
rename from core/res/res/layout/time_picker_legacy_holo.xml
rename to core/res/res/layout/time_picker_legacy_material.xml
diff --git a/core/res/res/layout/time_picker_holo.xml b/core/res/res/layout/time_picker_material.xml
similarity index 80%
rename from core/res/res/layout/time_picker_holo.xml
rename to core/res/res/layout/time_picker_material.xml
index cb25dbe..37a7384 100644
--- a/core/res/res/layout/time_picker_holo.xml
+++ b/core/res/res/layout/time_picker_material.xml
@@ -22,7 +22,7 @@
     android:layout_height="match_parent"
     android:orientation="vertical">
     <include
-        layout="@layout/time_header_label"
+        layout="@layout/time_picker_header_material"
         android:layout_width="match_parent"
         android:layout_height="@dimen/timepicker_header_height"
         android:layout_gravity="center" />
@@ -31,7 +31,7 @@
         android:layout_width="wrap_content"
         android:layout_height="@dimen/timepicker_radial_picker_dimen"
         android:layout_gravity="center"
-        android:layout_marginTop="?attr/dialogPreferredPadding"
-        android:layout_marginStart="?attr/dialogPreferredPadding"
-        android:layout_marginEnd="?attr/dialogPreferredPadding" />
+        android:layout_marginTop="@dimen/timepicker_radial_picker_top_margin"
+        android:layout_marginStart="@dimen/timepicker_radial_picker_horizontal_margin"
+        android:layout_marginEnd="@dimen/timepicker_radial_picker_horizontal_margin" />
 </LinearLayout>
diff --git a/core/res/res/values-h320dp/bools.xml b/core/res/res/values-h320dp/bools.xml
index 8dbc2e1..3bbfe96 100644
--- a/core/res/res/values-h320dp/bools.xml
+++ b/core/res/res/values-h320dp/bools.xml
@@ -1,21 +1,20 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/*
-** Copyright 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.
-*/
+     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.
 -->
+
 <resources>
     <bool name="allow_stacked_button_bar">true</bool>
 </resources>
diff --git a/core/res/res/values-h320dp/dimens.xml b/core/res/res/values-h320dp/dimens.xml
new file mode 100644
index 0000000..d0de6a1
--- /dev/null
+++ b/core/res/res/values-h320dp/dimens.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     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.
+-->
+
+<resources>
+    <!-- Used by RadialTimePicker in clock-style TimePicker. -->
+    <dimen name="timepicker_text_inset_inner">58dp</dimen>
+    <dimen name="timepicker_radial_picker_dimen">224dp</dimen>
+    <integer name="timepicker_title_visibility">2</integer>
+
+    <dimen name="floating_window_margin_left">16dp</dimen>
+    <dimen name="floating_window_margin_top">8dp</dimen>
+    <dimen name="floating_window_margin_right">16dp</dimen>
+    <dimen name="floating_window_margin_bottom">32dp</dimen>
+</resources>
diff --git a/core/res/res/values-land/dimens_material.xml b/core/res/res/values-land/dimens_material.xml
index 77719a6..379ccf6 100644
--- a/core/res/res/values-land/dimens_material.xml
+++ b/core/res/res/values-land/dimens_material.xml
@@ -24,4 +24,28 @@
     <!-- Default text size for action bar subtitle.-->
     <dimen name="text_size_subtitle_material_toolbar">12dp</dimen>
 
+    <!-- Floating window margins are small until we hit sw380dp-land. -->
+    <dimen name="floating_window_margin_left">16dp</dimen>
+    <dimen name="floating_window_margin_top">4dp</dimen>
+    <dimen name="floating_window_margin_right">16dp</dimen>
+    <dimen name="floating_window_margin_bottom">16dp</dimen>
+
+    <!-- Material time picker dimensions. -->
+    <!-- Text size for the time picker header HH:MM label. This value is large
+         enough that we don't need to use scaled pixels, dp is fine. -->
+    <dimen name="timepicker_time_label_size">48dp</dimen>
+    <dimen name="timepicker_ampm_label_size">16sp</dimen>
+    <dimen name="timepicker_am_top_padding">8dp</dimen>
+    <dimen name="timepicker_pm_top_padding">3dp</dimen>
+    <!-- Radial picker is small until we hit sw380dp-land. -->
+    <dimen name="timepicker_radial_picker_dimen">180dp</dimen>
+    <dimen name="timepicker_radial_picker_top_margin">16dp</dimen>
+    <dimen name="timepicker_radial_picker_horizontal_margin">24dp</dimen>
+
+    <!-- Used by RadialTimePicker in clock-style TimePicker. -->
+    <dimen name="timepicker_text_inset_normal">22dp</dimen>
+    <!-- Landscape inset is small until we hit sw380dp-land. -->
+    <dimen name="timepicker_text_inset_inner">46dp</dimen>
+    <dimen name="timepicker_text_size_normal">14sp</dimen>
+    <dimen name="timepicker_text_size_inner">12sp</dimen>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 09103e3..b3c60ad 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4471,10 +4471,6 @@
         <attr name="headerYearTextAppearance" format="reference" />
         <!-- The background for the date selector. -->
         <attr name="headerBackground" />
-        <!-- @hide The selected text color for the date selector. Used as a
-             backup if the text appearance does not explicitly have a color
-             set for the selected state. -->
-        <attr name="headerSelectedTextColor" />
         <!-- The list year's text appearance in the list. -->
         <attr name="yearListItemTextAppearance" format="reference" />
         <!-- The list year's selected circle color in the list. -->
@@ -4774,10 +4770,6 @@
         <attr name="headerAmPmTextAppearance" format="reference" />
         <!-- The text appearance for the time header. -->
         <attr name="headerTimeTextAppearance" format="reference" />
-        <!-- @hide The text color for selected time header of the TimePicker.
-             This will override the value from the text appearance if it does
-             not explicitly have a color set for the selected state. -->
-        <attr name="headerSelectedTextColor" format="color" />
         <!-- The background for the header containing the currently selected time. -->
         <attr name="headerBackground" />
         <!-- The color for the hours/minutes numbers. -->
@@ -4790,10 +4782,6 @@
         <attr name="amPmTextColor" format="color" />
         <!-- The background color state list for the AM/PM selectors. -->
         <attr name="amPmBackgroundColor" format="color" />
-        <!-- @hide The background color for the AM/PM selectors of the
-             TimePicker when selected. Used if the background color does not
-             explicitly have a color set for the selected state. -->
-        <attr name="amPmSelectedBackgroundColor" format="color" />
         <!-- The color for the hours/minutes selector. -->
         <attr name="numbersSelectorColor" format="color" />
         <!-- Defines the look of the widget. Prior to the L release, the only choice was
@@ -6459,6 +6447,33 @@
              for more info. -->
         <attr name="actionProviderClass" format="string" />
 
+        <!-- An optional tint for the item's icon.
+             See {@link android.view.MenuItem#setIconTintList(android.content.res.ColorStateList)}
+             for more info. -->
+        <attr name="iconTint" format="color" />
+
+        <!-- The blending mode used for tinting the item's icon
+             See {@link android.view.MenuItem#setIconTintMode(android.graphics.PorterDuff.Mode)}
+             for more info. -->
+        <attr name="iconTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
     </declare-styleable>
 
     <!-- Attrbitutes for a ActvityChooserView. -->
@@ -7562,6 +7577,52 @@
         <!-- Text to set as the content description for the navigation button
              located at the start of the toolbar. -->
         <attr name="navigationContentDescription" format="string" />
+
+        <!-- Tint used for the navigation button -->
+        <attr name="navigationTint" format="color" />
+        <!-- The blending mode used for tinting the navigation button -->
+        <attr name="navigationTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D). Only works on APIv 11+ -->
+            <enum name="add" value="16" />
+        </attr>
+
+        <!-- Tint used for the overflow button -->
+        <attr name="overflowTint" format="color" />
+        <!-- The blending mode used for tinting the overflow button -->
+        <attr name="overflowTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and drawable color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D). Only works on APIv 11+ -->
+            <enum name="add" value="16" />
+        </attr>
     </declare-styleable>
 
     <declare-styleable name="Toolbar_LayoutParams">
diff --git a/core/res/res/values/colors_holo.xml b/core/res/res/values/colors_holo.xml
index eab1e3f..c29fec6 100644
--- a/core/res/res/values/colors_holo.xml
+++ b/core/res/res/values/colors_holo.xml
@@ -103,46 +103,4 @@
     <color name="group_button_dialog_pressed_holo_light">#ffffffff</color>
     <color name="group_button_dialog_focused_holo_light">#4699cc00</color>
 
-    <!-- Time picker -->
-    <eat-comment />
-
-    <color name="timepicker_default_background_holo_light">@color/white</color>
-    <color name="timepicker_default_background_holo_dark">#ff303030</color>
-
-    <color name="timepicker_default_text_color_holo_light">#8c8c8c</color>
-    <color name="timepicker_default_text_color_holo_dark">@color/white</color>
-
-    <color name="timepicker_default_ampm_selected_background_color_holo_light">@color/holo_blue_light</color>
-    <color name="timepicker_default_ampm_selected_background_color_holo_dark">@color/holo_blue_light</color>
-
-    <color name="timepicker_default_ampm_unselected_background_color_holo_light">@color/white</color>
-    <color name="timepicker_default_ampm_unselected_background_color_holo_dark">@color/transparent</color>
-
-    <!-- DatePicker colors -->
-    <eat-comment />
-
-    <color name="datepicker_default_header_selector_background_holo_light">@android:color/white</color>
-    <color name="datepicker_default_header_selector_background_holo_dark">#ff303030</color>
-
-    <color name="datepicker_default_header_dayofweek_background_color_holo_light">#999999</color>
-    <color name="datepicker_default_header_dayofweek_background_color_holo_dark">@android:color/white</color>
-
-    <color name="datepicker_default_normal_text_color_holo_light">#ff999999</color>
-    <color name="datepicker_default_normal_text_color_holo_dark">@android:color/white</color>
-
-    <color name="datepicker_default_disabled_text_color_holo_light">#80999999</color>
-    <color name="datepicker_default_disabled_text_color_holo_dark">#80999999</color>
-
-    <color name="datepicker_default_selected_text_color_holo_light">#33b5e5</color>
-    <color name="datepicker_default_selected_text_color_holo_dark">#33b5e5</color>
-
-    <color name="datepicker_default_pressed_text_color_holo_light">#0099cc</color>
-    <color name="datepicker_default_pressed_text_color_holo_dark">#0099cc</color>
-
-    <color name="datepicker_default_circle_background_color_holo_light">@android:color/holo_blue_light</color>
-    <color name="datepicker_default_circle_background_color_holo_dark">@android:color/holo_blue_light</color>
-
-    <color name="datepicker_default_view_animator_color_holo_light">#f2f2f2</color>
-    <color name="datepicker_default_view_animator_color_holo_dark">#ff303030</color>
-
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index d240047..e8a249e 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -356,44 +356,6 @@
     <!-- Outline width for video subtitles. -->
     <dimen name="subtitle_outline_width">2dp</dimen>
 
-    <!-- New TimePicker dimensions. -->
-    <dimen name="timepicker_selector_radius">24dp</dimen>
-    <dimen name="timepicker_center_dot_radius">4dp</dimen>
-    <dimen name="timepicker_selector_dot_radius">4dp</dimen>
-    <dimen name="timepicker_text_inset_normal">26dp</dimen>
-    <dimen name="timepicker_text_inset_inner">58dp</dimen>
-    <dimen name="timepicker_text_size_normal">14sp</dimen>
-    <dimen name="timepicker_text_size_inner">12sp</dimen>
-
-    <!-- Text size for the time picker header HH:MM label. This value is large
-         enough that we don't need to use scaled pixels, dp is fine. -->
-    <dimen name="timepicker_time_label_size">60dp</dimen>
-    <dimen name="timepicker_ampm_label_size">16sp</dimen>
-    <dimen name="timepicker_ampm_horizontal_padding">12dp</dimen>
-    <dimen name="timepicker_ampm_vertical_padding">16dp</dimen>
-    <dimen name="timepicker_pm_top_padding">3dp</dimen>
-    <dimen name="timepicker_separator_padding">4dp</dimen>
-    <dimen name="timepicker_header_height">96dp</dimen>
-    <dimen name="timepicker_radial_picker_dimen">270dp</dimen>
-
-    <!-- Used by SimpleMonthView -->
-    <dimen name="datepicker_day_number_size">12sp</dimen>
-    <dimen name="datepicker_month_label_size">14sp</dimen>
-    <dimen name="datepicker_month_day_label_text_size">12sp</dimen>
-    <dimen name="datepicker_month_list_item_header_height">48dp</dimen>
-    <dimen name="datepicker_view_animator_height">226dp</dimen>
-
-    <dimen name="datepicker_year_picker_padding_top">8dp</dimen>
-    <dimen name="datepicker_year_label_height">64dp</dimen>
-    <dimen name="datepicker_year_label_text_size">22dp</dimen>
-    <dimen name="datepicker_component_width">260dp</dimen>
-    <dimen name="datepicker_dialog_width">520dp</dimen>
-    <dimen name="datepicker_selected_date_day_size">88dp</dimen>
-    <dimen name="datepicker_selected_date_month_size">24dp</dimen>
-    <dimen name="datepicker_selected_date_year_size">24dp</dimen>
-    <dimen name="datepicker_header_height">30dp</dimen>
-    <dimen name="datepicker_header_text_size">14dp</dimen>
-
     <!-- Minimum size of the fast scroller thumb's touch target. -->
     <dimen name="fast_scroller_minimum_touch_target">48dp</dimen>
 
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index b84249a..8d2afde 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -117,4 +117,47 @@
 
     <dimen name="scrubber_track_height_material">2dp</dimen>
     <dimen name="progress_bar_height_material">4dp</dimen>
+
+    <!-- Material time picker dimensions. -->
+    <!-- Text size for the time picker header HH:MM label. This value is large
+         enough that we don't need to use scaled pixels, dp is fine. -->
+    <dimen name="timepicker_time_label_size">60dp</dimen>
+    <dimen name="timepicker_ampm_label_size">16sp</dimen>
+    <dimen name="timepicker_ampm_horizontal_padding">16dp</dimen>
+    <dimen name="timepicker_am_top_padding">4dp</dimen>
+    <dimen name="timepicker_pm_top_padding">4dp</dimen>
+    <dimen name="timepicker_separator_padding">2dp</dimen>
+    <dimen name="timepicker_header_height">96dp</dimen>
+    <dimen name="timepicker_radial_picker_dimen">296dp</dimen>
+    <dimen name="timepicker_radial_picker_top_margin">16dp</dimen>
+    <dimen name="timepicker_radial_picker_horizontal_margin">16dp</dimen>
+
+    <!-- Used by RadialTimePicker in clock-style TimePicker. -->
+    <dimen name="timepicker_selector_radius">20dp</dimen>
+    <dimen name="timepicker_selector_stroke">2dp</dimen>
+    <dimen name="timepicker_center_dot_radius">3dp</dimen>
+    <dimen name="timepicker_selector_dot_radius">3dp</dimen>
+    <dimen name="timepicker_text_inset_normal">22dp</dimen>
+    <dimen name="timepicker_text_inset_inner">58dp</dimen>
+    <dimen name="timepicker_text_size_normal">16sp</dimen>
+    <dimen name="timepicker_text_size_inner">12sp</dimen>
+
+    <!-- Material date picker dimensions. -->
+    <dimen name="datepicker_year_picker_padding_top">8dp</dimen>
+    <dimen name="datepicker_year_label_height">64dp</dimen>
+    <dimen name="datepicker_year_label_text_size">22dp</dimen>
+    <dimen name="datepicker_component_width">260dp</dimen>
+    <dimen name="datepicker_dialog_width">520dp</dimen>
+    <dimen name="datepicker_selected_date_day_size">88dp</dimen>
+    <dimen name="datepicker_selected_date_month_size">24dp</dimen>
+    <dimen name="datepicker_selected_date_year_size">24dp</dimen>
+    <dimen name="datepicker_header_height">30dp</dimen>
+    <dimen name="datepicker_header_text_size">14dp</dimen>
+
+    <!-- Used by Material-style SimpleMonthView -->
+    <dimen name="datepicker_day_number_size">12sp</dimen>
+    <dimen name="datepicker_month_label_size">14sp</dimen>
+    <dimen name="datepicker_month_day_label_text_size">12sp</dimen>
+    <dimen name="datepicker_month_list_item_header_height">48dp</dimen>
+    <dimen name="datepicker_view_animator_height">226dp</dimen>
 </resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index b6e79ad..d657bad 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -89,7 +89,7 @@
   <item type="id" name="parentMatrix" />
   <item type="id" name="statusBarBackground" />
   <item type="id" name="navigationBarBackground" />
+  <item type="id" name="pasteAsPlainText" />
   <item type="id" name="undo" />
   <item type="id" name="redo" />
-  <item type="id" name="pasteAsPlainText" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index af4922f..37f8232 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2615,6 +2615,12 @@
   <public type="attr" name="end" />
   <public type="attr" name="windowHasLightStatusBar" />
   <public type="attr" name="numbersInnerTextColor" />
+  <public type="attr" name="iconTint" />
+  <public type="attr" name="iconTintMode" />
+  <public type="attr" name="overflowTint" />
+  <public type="attr" name="overflowTintMode" />
+  <public type="attr" name="navigationTint" />
+  <public type="attr" name="navigationTintMode" />
 
   <public type="style" name="Widget.Material.Button.Colored" />
 
@@ -2634,13 +2640,14 @@
   <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 "Paste as plain text" menu item to to copy the current contents
+          of the clipboard into the text view without formatting. -->
+  <public type="id" name="pasteAsPlainText" />
   <!-- Context menu ID for the "Undo" menu item to undo the last text edit operation. -->
   <public type="id" name="undo" />
   <!-- Context menu ID for the "Redo" menu item to redo the last text edit operation. -->
   <public type="id" name="redo" />
-  <!-- Context menu ID for the "Paste as plain text" menu item to to copy the current contents
-          of the clipboard into the text view without formatting. -->
-  <public type="id" name="pasteAsPlainText" />
-
+ 
 </resources>
diff --git a/core/res/res/values/styles_holo.xml b/core/res/res/values/styles_holo.xml
index 4589fa3..6861069 100644
--- a/core/res/res/values/styles_holo.xml
+++ b/core/res/res/values/styles_holo.xml
@@ -463,40 +463,14 @@
         <item name="virtualButtonPressedDrawable">?attr/selectableItemBackground</item>
     </style>
 
-    <style name="Widget.Holo.TimePicker" parent="Widget.TimePicker">
+    <style name="Widget.Holo.TimePicker" parent="Widget.Material.TimePicker">
+        <!-- If the developer chooses "clock", they get the Material picker. -->
         <item name="timePickerMode">spinner</item>
-        <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
-        <!-- Attributes for new-style TimePicker. -->
-        <item name="internalLayout">@layout/time_picker_holo</item>
-        <item name="headerTimeTextAppearance">@style/TextAppearance.Holo.TimePicker.TimeLabel</item>
-        <item name="headerAmPmTextAppearance">@style/TextAppearance.Holo.TimePicker.AmPmLabel</item>
-        <item name="headerBackground">@color/timepicker_default_background_holo_dark</item>
-        <item name="headerSelectedTextColor">@color/holo_blue_light</item>
-        <item name="numbersTextColor">@color/timepicker_default_text_color_holo_dark</item>
-        <item name="numbersBackgroundColor">@color/timepicker_default_background_holo_dark</item>
-        <item name="amPmTextColor">@color/timepicker_default_text_color_holo_dark</item>
-        <item name="amPmBackgroundColor">@color/timepicker_default_background_holo_dark</item>
-        <item name="amPmSelectedBackgroundColor">@color/holo_blue_light</item>
-        <item name="numbersSelectorColor">@color/holo_blue_light</item>
     </style>
 
-    <style name="Widget.Holo.DatePicker" parent="Widget.DatePicker">
+    <style name="Widget.Holo.DatePicker" parent="Widget.Material.DatePicker">
+        <!-- If the developer chooses "calendar", they get the Material picker. -->
         <item name="datePickerMode">spinner</item>
-        <item name="legacyLayout">@layout/date_picker_legacy_holo</item>
-        <item name="internalLayout">@layout/date_picker_holo</item>
-        <item name="calendarViewShown">true</item>
-        <!-- New-style date picker attributes. -->
-        <item name="dayOfWeekBackground">@color/datepicker_default_header_dayofweek_background_color_holo_dark</item>
-        <item name="dayOfWeekTextAppearance">@style/TextAppearance.Holo.DatePicker.DayOfWeekLabel</item>
-        <item name="headerBackground">@color/datepicker_default_header_selector_background_holo_dark</item>
-        <item name="headerMonthTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.MonthLabel</item>
-        <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.DayOfMonthLabel</item>
-        <item name="headerYearTextAppearance">@style/TextAppearance.Holo.DatePicker.Selector.YearLabel</item>
-        <item name="headerSelectedTextColor">@color/holo_blue_light</item>
-        <item name="yearListItemTextAppearance">@style/TextAppearance.Holo.DatePicker.List.YearLabel</item>
-        <item name="yearListSelectorColor">@color/datepicker_default_circle_background_color_holo_dark</item>
-        <item name="calendarTextColor">@color/date_picker_calendar_holo_dark</item>
-        <item name="calendarDayBackgroundColor">@color/holo_blue_dark</item>
     </style>
 
     <style name="Widget.Holo.ActivityChooserView" parent="Widget.ActivityChooserView" />
@@ -888,40 +862,14 @@
 
     <style name="Widget.Holo.Light.NumberPicker" parent="Widget.Holo.NumberPicker" />
 
-    <style name="Widget.Holo.Light.TimePicker" parent="Widget.TimePicker">
+    <style name="Widget.Holo.Light.TimePicker" parent="Widget.Material.Light.TimePicker">
+        <!-- If the developer chooses "clock", they get the Material picker. -->
         <item name="timePickerMode">spinner</item>
-        <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
-        <!-- Non-legacy styling -->
-        <item name="internalLayout">@layout/time_picker_holo</item>
-        <item name="headerTimeTextAppearance">@style/TextAppearance.Holo.Light.TimePicker.TimeLabel</item>
-        <item name="headerAmPmTextAppearance">@style/TextAppearance.Holo.Light.TimePicker.AmPmLabel</item>
-        <item name="headerBackground">@color/timepicker_default_background_holo_light</item>
-        <item name="headerSelectedTextColor">@color/holo_blue_light</item>
-        <item name="numbersTextColor">@color/timepicker_default_text_color_holo_light</item>
-        <item name="numbersBackgroundColor">@color/timepicker_default_background_holo_light</item>
-        <item name="amPmTextColor">@color/timepicker_default_text_color_holo_light</item>
-        <item name="amPmBackgroundColor">@color/timepicker_default_background_holo_light</item>
-        <item name="amPmSelectedBackgroundColor">@color/holo_blue_light</item>
-        <item name="numbersSelectorColor">@color/holo_blue_light</item>
     </style>
 
-    <style name="Widget.Holo.Light.DatePicker" parent="Widget.DatePicker">
+    <style name="Widget.Holo.Light.DatePicker" parent="Widget.Material.Light.DatePicker">
+        <!-- If the developer chooses "calendar", they get the Material picker. -->
         <item name="datePickerMode">spinner</item>
-        <item name="legacyLayout">@layout/date_picker_legacy_holo</item>
-        <item name="internalLayout">@layout/date_picker_holo</item>
-        <item name="calendarViewShown">true</item>
-        <!-- New-style date picker attributes. -->
-        <item name="dayOfWeekBackground">@color/datepicker_default_header_dayofweek_background_color_holo_light</item>
-        <item name="dayOfWeekTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.DayOfWeekLabel</item>
-        <item name="headerMonthTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.MonthLabel</item>
-        <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.DayOfMonthLabel</item>
-        <item name="headerYearTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.Selector.YearLabel</item>
-        <item name="headerBackground">@color/datepicker_default_header_selector_background_holo_light</item>
-        <item name="headerSelectedTextColor">@color/holo_blue_light</item>
-        <item name="yearListItemTextAppearance">@style/TextAppearance.Holo.Light.DatePicker.List.YearLabel</item>
-        <item name="yearListSelectorColor">@color/datepicker_default_circle_background_color_holo_light</item>
-        <item name="calendarTextColor">@color/date_picker_calendar_holo_light</item>
-        <item name="calendarDayBackgroundColor">@color/holo_blue_light</item>
     </style>
 
     <style name="Widget.Holo.Light.ActivityChooserView" parent="Widget.Holo.ActivityChooserView">
@@ -1221,86 +1169,6 @@
         <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_holo_light</item>
     </style>
 
-    <style name="TextAppearance.Holo.TimePicker.TimeLabel" parent="TextAppearance.Holo">
-        <item name="textSize">@dimen/timepicker_time_label_size</item>
-        <item name="textColor">@color/timepicker_default_text_color_holo_dark</item>
-    </style>
-
-    <style name="TextAppearance.Holo.TimePicker.AmPmLabel" parent="TextAppearance.Holo">
-        <item name="textSize">@dimen/timepicker_ampm_label_size</item>
-        <item name="textAllCaps">true</item>
-        <item name="textColor">@color/timepicker_default_text_color_holo_dark</item>
-        <item name="textStyle">bold</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.TimePicker.TimeLabel" parent="TextAppearance.Holo.Light">
-        <item name="textSize">@dimen/timepicker_time_label_size</item>
-        <item name="textColor">@color/timepicker_default_text_color_holo_light</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.TimePicker.AmPmLabel" parent="TextAppearance.Holo.Light">
-        <item name="textSize">@dimen/timepicker_ampm_label_size</item>
-        <item name="textAllCaps">true</item>
-        <item name="textColor">@color/timepicker_default_text_color_holo_light</item>
-        <item name="textStyle">bold</item>
-    </style>
-
-    <style name="TextAppearance.Holo.DatePicker.DayOfWeekLabel" parent="TextAppearance.Holo">
-        <item name="includeFontPadding">false</item>
-        <item name="textColor">@color/black</item>
-        <item name="textSize">@dimen/datepicker_header_text_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.DatePicker.Selector" parent="TextAppearance.Holo">
-        <item name="includeFontPadding">false</item>
-        <item name="textColor">@color/date_picker_selector_holo_dark</item>
-    </style>
-
-    <style name="TextAppearance.Holo.DatePicker.Selector.MonthLabel" parent="TextAppearance.Holo.DatePicker.Selector">
-        <item name="textSize">@dimen/datepicker_selected_date_month_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.DatePicker.Selector.DayOfMonthLabel" parent="TextAppearance.Holo.DatePicker.Selector">
-        <item name="textSize">@dimen/datepicker_selected_date_day_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.DatePicker.Selector.YearLabel" parent="TextAppearance.Holo.DatePicker.Selector">
-        <item name="textSize">@dimen/datepicker_selected_date_year_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.DatePicker.List.YearLabel" parent="TextAppearance.Holo">
-        <item name="textColor">@color/date_picker_year_selector_holo_dark</item>
-        <item name="textSize">@dimen/datepicker_year_label_text_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.DatePicker.DayOfWeekLabel" parent="TextAppearance.Holo">
-        <item name="includeFontPadding">false</item>
-        <item name="textColor">@color/white</item>
-        <item name="textSize">@dimen/datepicker_header_text_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.DatePicker.Selector" parent="TextAppearance.Holo">
-        <item name="includeFontPadding">false</item>
-        <item name="textColor">@color/date_picker_selector_holo_light</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.DatePicker.Selector.MonthLabel" parent="TextAppearance.Holo.Light.DatePicker.Selector">
-        <item name="textSize">@dimen/datepicker_selected_date_month_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.DatePicker.Selector.DayOfMonthLabel" parent="TextAppearance.Holo.Light.DatePicker.Selector">
-        <item name="textSize">@dimen/datepicker_selected_date_day_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.DatePicker.Selector.YearLabel" parent="TextAppearance.Holo.Light.DatePicker.Selector">
-        <item name="textSize">@dimen/datepicker_selected_date_year_size</item>
-    </style>
-
-    <style name="TextAppearance.Holo.Light.DatePicker.List.YearLabel" parent="TextAppearance.Holo">
-        <item name="textColor">@color/date_picker_year_selector_holo_light</item>
-        <item name="textSize">@dimen/datepicker_year_label_text_size</item>
-    </style>
-
     <style name="Widget.Holo.FastScroll" parent="Widget.FastScroll">
         <item name="thumbMinWidth">0dp</item>
         <item name="thumbMinHeight">0dp</item>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index d75e496..a8ab18d 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -37,7 +37,7 @@
     </style>
 
     <style name="PreferenceFragment.Material">
-        <item name="layout">@android:layout/preference_list_fragment_material</item>
+        <item name="layout">@layout/preference_list_fragment_material</item>
         <item name="paddingStart">@dimen/preference_fragment_padding_side_material</item>
         <item name="paddingEnd">@dimen/preference_fragment_padding_side_material</item>
     </style>
@@ -72,7 +72,7 @@
     </style>
 
     <style name="Preference.Material.SeekBarPreference">
-        <item name="layout">@android:layout/preference_widget_seekbar_material</item>
+        <item name="layout">@layout/preference_widget_seekbar_material</item>
     </style>
 
     <style name="Preference.Material.PreferenceScreen"/>
@@ -379,14 +379,12 @@
 
     <style name="TextAppearance.Material.TimePicker.TimeLabel" parent="TextAppearance.Material">
         <item name="textSize">@dimen/timepicker_time_label_size</item>
-        <item name="textColor">?attr/textColorSecondaryInverse</item>
+        <item name="textColor">@color/time_picker_header_text_material</item>
     </style>
 
-    <style name="TextAppearance.Material.TimePicker.AmPmLabel" parent="TextAppearance.Material">
+    <style name="TextAppearance.Material.TimePicker.AmPmLabel" parent="TextAppearance.Material.Button">
         <item name="textSize">@dimen/timepicker_ampm_label_size</item>
-        <item name="textAllCaps">true</item>
-        <item name="textColor">?attr/textColorSecondaryInverse</item>
-        <item name="textStyle">bold</item>
+        <item name="textColor">@color/time_picker_header_text_material</item>
     </style>
 
     <style name="TextAppearance.Material.DatePicker.DayOfWeekLabel" parent="TextAppearance.Material">
@@ -397,19 +395,19 @@
 
     <style name="TextAppearance.Material.DatePicker.MonthLabel" parent="TextAppearance.Material">
         <item name="includeFontPadding">false</item>
-        <item name="textColor">?attr/textColorSecondaryInverse</item>
+        <item name="textColor">@color/date_picker_header_text_material</item>
         <item name="textSize">@dimen/datepicker_selected_date_month_size</item>
     </style>
 
     <style name="TextAppearance.Material.DatePicker.DayOfMonthLabel" parent="TextAppearance.Material">
         <item name="includeFontPadding">false</item>
-        <item name="textColor">?attr/textColorSecondaryInverse</item>
+        <item name="textColor">@color/date_picker_header_text_material</item>
         <item name="textSize">@dimen/datepicker_selected_date_day_size</item>
     </style>
 
     <style name="TextAppearance.Material.DatePicker.YearLabel" parent="TextAppearance.Material">
         <item name="includeFontPadding">false</item>
-        <item name="textColor">?attr/textColorSecondaryInverse</item>
+        <item name="textColor">@color/date_picker_header_text_material</item>
         <item name="textSize">@dimen/datepicker_selected_date_year_size</item>
     </style>
 
@@ -513,9 +511,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>
@@ -644,36 +640,32 @@
         <item name="virtualButtonPressedDrawable">?attr/selectableItemBackground</item>
     </style>
 
-    <style name="Widget.Material.TimePicker" parent="Widget.TimePicker">
+    <style name="Widget.Material.TimePicker">
         <item name="timePickerMode">clock</item>
-        <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
+        <item name="legacyLayout">@layout/time_picker_legacy_material</item>
         <!-- Attributes for new-style TimePicker. -->
-        <item name="internalLayout">@layout/time_picker_holo</item>
+        <item name="internalLayout">@layout/time_picker_material</item>
         <item name="headerTimeTextAppearance">@style/TextAppearance.Material.TimePicker.TimeLabel</item>
         <item name="headerAmPmTextAppearance">@style/TextAppearance.Material.TimePicker.AmPmLabel</item>
-        <item name="headerSelectedTextColor">?attr/textColorPrimaryInverse</item>
         <item name="headerBackground">@drawable/time_picker_header_material</item>
         <item name="numbersTextColor">?attr/textColorPrimaryActivated</item>
         <item name="numbersInnerTextColor">?attr/textColorSecondaryActivated</item>
         <item name="numbersBackgroundColor">#10ffffff</item>
         <item name="numbersSelectorColor">?attr/colorControlActivated</item>
         <item name="amPmTextColor">?attr/textColorSecondary</item>
-        <item name="amPmBackgroundColor">@color/transparent</item>
-        <item name="amPmSelectedBackgroundColor">?attr/colorControlActivated</item>
     </style>
 
-    <style name="Widget.Material.DatePicker" parent="Widget.DatePicker">
+    <style name="Widget.Material.DatePicker">
         <item name="datePickerMode">calendar</item>
         <item name="legacyLayout">@layout/date_picker_legacy_holo</item>
+        <item name="calendarViewShown">true</item>
         <!-- Attributes for new-style DatePicker. -->
         <item name="internalLayout">@layout/date_picker_holo</item>
-        <item name="calendarViewShown">true</item>
         <item name="dayOfWeekBackground">#10000000</item>
         <item name="dayOfWeekTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfWeekLabel</item>
         <item name="headerMonthTextAppearance">@style/TextAppearance.Material.DatePicker.MonthLabel</item>
         <item name="headerDayOfMonthTextAppearance">@style/TextAppearance.Material.DatePicker.DayOfMonthLabel</item>
         <item name="headerYearTextAppearance">@style/TextAppearance.Material.DatePicker.YearLabel</item>
-        <item name="headerSelectedTextColor">?attr/textColorPrimaryInverse</item>
         <item name="headerBackground">?attr/colorAccent</item>
         <item name="yearListItemTextAppearance">@style/TextAppearance.Material.DatePicker.List.YearLabel</item>
         <item name="yearListSelectorColor">?attr/colorControlActivated</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 39c0e8f..86e46f6 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1975,10 +1975,8 @@
 
   <java-symbol type="attr" name="nestedScrollingEnabled" />
 
-  <java-symbol type="style" name="TextAppearance.Holo.TimePicker.TimeLabel" />
-
-  <java-symbol type="layout" name="time_picker_holo" />
-  <java-symbol type="layout" name="time_header_label" />
+  <java-symbol type="layout" name="time_picker_material" />
+  <java-symbol type="layout" name="time_picker_header_material" />
   <java-symbol type="layout" name="year_label_text_view" />
   <java-symbol type="layout" name="date_picker_holo" />
 
@@ -2045,22 +2043,6 @@
   <java-symbol type="dimen" name="datepicker_year_label_height" />
   <java-symbol type="dimen" name="datepicker_year_picker_padding_top" />
 
-  <java-symbol type="color" name="timepicker_default_text_color_holo_light" />
-  <java-symbol type="color" name="timepicker_default_ampm_unselected_background_color_holo_light" />
-  <java-symbol type="color" name="timepicker_default_ampm_selected_background_color_holo_light" />
-
-  <java-symbol type="color" name="datepicker_default_normal_text_color_holo_light" />
-  <java-symbol type="color" name="datepicker_default_disabled_text_color_holo_light" />
-  <java-symbol type="color" name="datepicker_default_circle_background_color_holo_light" />
-  <java-symbol type="color" name="datepicker_default_header_dayofweek_background_color_holo_light" />
-  <java-symbol type="color" name="datepicker_default_header_selector_background_holo_light" />
-
-  <java-symbol type="color" name="datepicker_default_normal_text_color_material_light" />
-  <java-symbol type="color" name="datepicker_default_disabled_text_color_material_light" />
-  <java-symbol type="color" name="datepicker_default_circle_background_color_material_light" />
-  <java-symbol type="color" name="datepicker_default_header_dayofweek_background_color_material_light" />
-  <java-symbol type="color" name="datepicker_default_header_selector_background_material_light" />
-
   <java-symbol type="array" name="config_clockTickVibePattern" />
   <java-symbol type="array" name="config_calendarDateVibePattern" />
 
@@ -2106,8 +2088,6 @@
   <java-symbol type="attr" name="ambientShadowAlpha" />
   <java-symbol type="attr" name="spotShadowAlpha" />
   <java-symbol type="array" name="config_cdma_home_system" />
-  <java-symbol type="attr" name="headerSelectedTextColor" />
-  <java-symbol type="attr" name="amPmSelectedBackgroundColor" />
   <java-symbol type="bool" name="config_sms_decode_gsm_8bit_data" />
   <java-symbol type="dimen" name="text_size_small_material" />
   <java-symbol type="attr" name="checkMarkGravity" />
@@ -2169,4 +2149,5 @@
 
   <java-symbol type="integer" name="config_screen_magnification_multi_tap_adjustment" />
   <java-symbol type="dimen" name="config_screen_magnification_scaling_threshold" />
+  <java-symbol type="dimen" name="timepicker_selector_stroke"/>
 </resources>
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/docs/html-intl/intl/ja/distribute/index.jd b/docs/html-intl/intl/ja/distribute/index.jd
new file mode 100644
index 0000000..27f1cb4
--- /dev/null
+++ b/docs/html-intl/intl/ja/distribute/index.jd
@@ -0,0 +1,16 @@
+page.title=Google Play でアプリを配信する
+page.viewport_width=970
+section.landing=true
+header.hide=1
+nonavpage=true
+page.metaDescription=Google Play は最もよく利用されている Android アプリストアです。クラウドと同期された強力な基盤により、ユーザーは簡単に あなたのアプリを見つけてダウンロードできます。
+
+@jd:body
+
+  <div class="resource-widget resource-flow-layout col-16"
+    style="margin-top:20px"
+    data-query="collection:launch/static/ja"
+    data-sortOrder=""
+    data-cardSizes="6x6,6x6,6x2x3,12x6,6x6,6x2x3,6x6,6x6,12x6,6x6"
+    data-maxResults="24"></div>
+
diff --git a/docs/html-intl/intl/ja/training/tv/start/index.jd b/docs/html-intl/intl/ja/training/tv/start/index.jd
index 8f946a1..e8db099 100755
--- a/docs/html-intl/intl/ja/training/tv/start/index.jd
+++ b/docs/html-intl/intl/ja/training/tv/start/index.jd
@@ -1,5 +1,7 @@
-page.title=TV アプリのビルド
+page.title=Android TV アプリ開発
 page.tags=tv, leanback
+page.metaDescription=Android TV 対応アプリ開発の手順が日本語化。
+page.image=design/tv/images/atv-home.jpg
 startpage=true
 
 @jd:body
diff --git a/docs/html/google/play/billing/billing_reference.jd b/docs/html/google/play/billing/billing_reference.jd
index da9178d..01e680f 100644
--- a/docs/html/google/play/billing/billing_reference.jd
+++ b/docs/html/google/play/billing/billing_reference.jd
@@ -12,6 +12,7 @@
     <ol>
       <li><a href="#getSkuDetails">getSkuDetails()</a></li>
       <li><a href="#getBuyIntent">getBuyIntent()</a></li>
+      <li><a href="#upgrade-getBuyIntentToReplaceSkus">getBuyIntentToReplaceSkus()</a></li>
       <li><a href="#getPurchases">getPurchases()</a></li>
     </ol>
     </li>
@@ -107,8 +108,8 @@
   </tr>
   <tr>
     <td>{@code type}</td>
-    <td>Value must be “inapp” for an in-app product or "subs" for
-subscriptions.</td>
+    <td>Value must be <code>“inapp”</code> for an in-app product or
+      <code>"subs"</code> for subscriptions.</td>
   </tr>
   <tr>
     <td>{@code price}</td>
@@ -140,7 +141,17 @@
 </p>
 
 <h3 id="getBuyIntent">The getBuyIntent() method</h3>
-<p>This method returns a response code integer mapped to the {@code RESPONSE_CODE} key, and a {@code PendingIntent} to launch the puchase flow for the in-app item mapped to the {@code BUY_INTENT} key. When it receives the {@code PendingIntent}, Google Play sends a response {@code Intent} with the data for that purchase order.  The data that is returned in the response {@code Intent} is summarized in table 3.</p>
+<p>
+  This method returns a response code integer mapped to the {@code
+  RESPONSE_CODE} key, and a {@link android.app.PendingIntent} to launch the
+  purchase flow for the in-app item mapped to the {@code BUY_INTENT} key, as
+  described in <a href=
+  "{@docRoot}google/play/billing/billing_integrate.html#purchase">Purchasing an
+  Item</a>. When it receives the {@link android.app.PendingIntent}, Google Play
+  sends a response {@code Intent} with the data for that purchase order. The
+  data that is returned in the response {@code Intent} is summarized in table
+  3.
+</p>
 
 <p class="table-caption" id="purchase-pendingintent-response-table">
 <strong>Table 3.</strong>  Response data from an In-app Billing Version 3 purchase request.</p>
@@ -151,7 +162,7 @@
   </tr>
   <tr>
     <td>{@code RESPONSE_CODE}</td>
-    <td>0 if the purchase was success, error otherwise.</td>
+    <td>Value is <code>0</code> if the purchase was success, error otherwise.</td>
   </tr>
   <tr>
     <td>{@code INAPP_PURCHASE_DATA}</td>
@@ -176,9 +187,22 @@
     <th scope="col">Field</th>
     <th scope="col">Description</th>
   </tr>
+    <tr>
+    <td>{@code autoRenewing}</td>
+    <td>Indicates whether the subscription renews automatically. If
+      <code>true</code>, the subscription is active, and will
+      automatically renew on the next billing date. If <code>false</code>,
+      indicates that the user has canceled the subscription. The user has
+      access to subscription content until the next billing date and will
+      lose access at that time unless they re-enable automatic renewal
+      (or manually renew, as described in
+      <a href="{@docRoot}google/play/billing/billing_subscriptions.html#manual-renewal">Manual
+      Renewal</a>).</td>
+  </tr>
   <tr>
     <td>{@code orderId}</td>
-    <td>A unique order identifier for the transaction. This corresponds to the Google Wallet Order ID.</td>
+    <td>A unique order identifier for the transaction. This identifier
+      corresponds to the Google Wallet Order ID.</td>
   </tr>
   <tr>
     <td>{@code packageName}</td>
@@ -194,7 +218,8 @@
   </tr>
   <tr>
     <td>{@code purchaseState}</td>
-    <td>The purchase state of the order. Possible values are 0 (purchased), 1 (canceled), or 2 (refunded).</td>
+    <td>The purchase state of the order. Possible values are <code>0</code>
+      (purchased), <code>1</code> (canceled), or <code>2</code> (refunded).</td>
   </tr>
   <tr>
     <td>{@code developerPayload}</td>
@@ -202,20 +227,48 @@
   </tr>
   <tr>
     <td>{@code purchaseToken}</td>
-    <td>A token that uniquely identifies a purchase for a given item and user
-    pair. This token may be up to 1,000 characters long.
-    Pass this entire token to other methods, such as when you consume the
-    purchase (as described in
-<a href="{@docRoot}training/in-app-billing/purchase-iab-products.html#Consume">Consume
-    a Purchase</a>). Do not abbreviate or truncate this token.</td>
+    <td>A token that uniquely identifies a purchase for a given item and user pair. </td>
   </tr>
 </table>
 </p>
 
-<h3 id="getPurchases">The getPurchases() method</h3>
-<p>This method returns the current un-consumed products owned by the user. Table 5 lists the response data that is returned in the {@code Bundle}.</p>
-<p class="table-caption" id="getpurchases-response-table">
-<strong>Table 5.</strong> Response data from a {@code getPurchases} request.</p>
+<h3 id="upgrade-getBuyIntentToReplaceSkus">The getBuyIntentToReplaceSkus()
+  method</h3>
+
+<p>This method is used to upgrade or downgrade a subscription purchase. The method
+is similar to <a href="#getBuyIntent"><code>getBuyIntent()</code></a>, except
+that it takes a list of already-purchased SKUs that are to be
+replaced with the SKU being purchased. When the user completes the purchase,
+Google Play cancels the old SKUs and credits the user with the unused value of
+their subscription time on a pro-rated basis. Google Play applies this credit
+to the new subscription, and does not begin billing the user for the new
+subscription until after the credit is used up.</p>
+
+<p>This method was added with version 5 of the in-app billing API. To verify
+that the method is reported, send an <code>isBillingSupported</code> AIDL
+request.</p>
+
+<p class="note"><strong>Note:</strong> You can only use this method for
+subscription purchases. If the passed <code>type</code> parameter is anything
+other than <code>"subs"</code>, the method returns
+<a href="#billing-codes"><code>BILLING_RESPONSE_RESULT_DEVELOPER_ERROR</code></a>.
+Furthermore, the passed SKUs may not include SKUs for seasonal
+subscriptions.</p>
+
+<p>
+  This method returns a response code integer mapped to the {@code
+  RESPONSE_CODE} key, and a {@link android.app.PendingIntent} to launch the
+  purchase flow for the in-app subscription mapped to the {@code BUY_INTENT}
+  key, as described in <a href=
+  "{@docRoot}google/play/billing/billing_integrate.html#purchase">Purchasing an
+  Item</a>. When it receives the {@link android.app.PendingIntent}, Google Play
+  sends a response {@code Intent} with the data for that purchase order. The
+  data that is returned in the response {@code Intent} is summarized in table
+  5.
+</p>
+
+<p class="table-caption" id="upgrade-purchase-pendingintent-response-table">
+<strong>Table 5.</strong> Response data from an In-app Billing Version 5 purchase request.</p>
 <table>
   <tr>
     <th scope="col">Key</th>
@@ -223,7 +276,39 @@
   </tr>
   <tr>
     <td>{@code RESPONSE_CODE}</td>
-    <td>0 if the request was successful, error otherwise.</td>
+    <td>Value is <code>0</code> if the purchase succeeds. If the purchase fails, contains an error
+      code.</td>
+  </tr>
+  <tr>
+    <td>{@code INAPP_PURCHASE_DATA}</td>
+    <td>
+       A String in JSON format that contains details about the purchase order.
+       See <a href="#purchase-data-table">table 4</a> for a description of the JSON fields.
+    </td>
+  </tr>
+  <tr>
+    <td>{@code INAPP_DATA_SIGNATURE}</td>
+    <td>String containing the signature of the purchase data that the developer
+      signed with their private key. The data signature uses the
+      RSASSA-PKCS1-v1_5 scheme.</td>
+  </tr>
+</table>
+</p>
+
+</p>
+
+<h3 id="getPurchases">The getPurchases() method</h3>
+<p>This method returns the current un-consumed products owned by the user. Table 5 lists the response data that is returned in the {@code Bundle}.</p>
+<p class="table-caption" id="getpurchases-response-table">
+<strong>Table 6.</strong> Response data from a {@code getPurchases} request.</p>
+<table>
+  <tr>
+    <th scope="col">Key</th>
+    <th scope="col">Description</th>
+  </tr>
+  <tr>
+    <td>{@code RESPONSE_CODE}</td>
+    <td>Value is <code>0</code> if the request was successful, error otherwise.</td>
   </tr>
   <tr>
     <td>{@code INAPP_PURCHASE_ITEM_LIST}</td>
diff --git a/docs/html/google/play/billing/billing_subscriptions.jd b/docs/html/google/play/billing/billing_subscriptions.jd
index b9b77df..8f55354e 100644
--- a/docs/html/google/play/billing/billing_subscriptions.jd
+++ b/docs/html/google/play/billing/billing_subscriptions.jd
@@ -1,4 +1,4 @@
-page.title=In-App Subscriptions
+page.title=In-app Subscriptions
 parent.title=In-app Billing
 parent.link=index.html
 page.metaDescription=Subscriptions let you sell content or features in your app with automated, recurring billing.
@@ -21,6 +21,11 @@
         Developer API</a>.</li>
     <li>Users purchase your subscriptions from inside your apps, rather than
         directly from Google Play.</li>
+    <li>Users can renew their subscriptions while a current subscription is
+        active.</li>
+    <li>Users can upgrade or downgrade a subscription in the middle of a
+        subscription period. The old subscription's cost is pro-rated, and the
+        unused portion is applied to the replacement subscription.</li>
     <li>You can defer billing for a particular user's subscription, to manage
         accounts or offer rewards.</li>
   </ul>
@@ -206,6 +211,65 @@
 billing errors that may occur. Your backend servers can use the server-side API 
 to query and update your records and follow up with customers directly, if needed.</p>
 
+<h3 id="manual-renewal">Manual Renewal</h3>
+
+<p>With version 5 of the In-app Billing API, users can renew a subscription
+during its active period even if the subscription is not set to
+automatically renew. If the user purchases a subscription while the subscription
+is active, it is extended by the appropriate period at the current rate.</p>
+
+<p>For example, Achilles has a subscription to the <em>Modern Hoplite</em> app.
+His subscription is currently due to expire on August 1. On July 10, he
+purchases a 3-month subscription at the current rate. Those three months are
+added to his existing subscription, so the subscription now expires on November
+1.</p>
+
+<p>It is up to the app to convey this with an appropriate UI. For example, if a
+user does not have an active subscription, the app might have a
+<strong>buy</strong> button, but if the user has a subscription the button might
+say <strong>renew</strong>.</p>
+
+<h3 id="upgrade">Subscription Upgrade/Downgrade</h3>
+
+<p>
+  With version 5 of the In-app Billing API, users can upgrade or downgrade a
+  subscription during its active period. When the user does this, the active
+  subscription is canceled and a new subscription is created. The unused
+  balance of the old subscription is applied on a pro-rated basis to the new
+  subscription. The first billing period for the new subscription begins after
+  that balance is used up. (The new subscription does not need to have a period
+  of the same length as the old one.)
+</p>
+
+<p>For example, Samwise has a subscription to online content from the
+<em>Country Gardener</em> app. He currently has a monthly subscription to the
+Tier 1
+version of the content (which has text-only content). This subscription costs
+him £2/month, and renews on the first of the month. On April
+15, he chooses to upgrade to the Tier 2 subscription (which includes video
+updates), costing £3/month. His Tier 1 subscription is immediately ended.
+Since he paid for a full month (April 1-30), but only used half of it, half of a
+month's subscription (£1) is applied to his new subscription. However, since
+that new subscription costs £3/month, the £1 credit balance only pays for ten
+days. So Samwise's credit pays for his subscription from April 15-25. On April
+26, he is charged £3 for his new subscription, and another £3 on the 26th of
+each month following.</p>
+
+<p class="note">
+  <strong>Note:</strong> The new subscription's billing date depends on when
+  the subscriber's pro-rated credit runs out, so the subscriber cannot upgrade
+  or downgrade to a seasonal subscription, which has fixed and predetermined
+  beginning and end dates.
+</p>
+
+<p>When a user upgrades or downgrades a subscription, your app calls
+<a href="{@docRoot}google/play/billing/billing_reference.html#upgrade-getBuyIntentToReplaceSkus">
+<code>getBuyIntentToReplaceSkus()</code></a>.
+This method is passed the new SKU the user wants to buy, and all
+the old SKUs that are superseded by it. The remaining portions of the old SKUs
+are used to pay for the new subscription, and billing begins when this credit
+is used up.</p>
+
 <h3 id="deferred-billing">Deferred Billing</h3>
 
 <p>Using the
@@ -316,7 +380,7 @@
 
 <p>When the user cancels a subscription, Google Play does not offer a refund for
 the current billing cycle. Instead, it allows the user to have access to the
-cancelled subscription until the end of the current billing cycle, at which time
+canceled subscription until the end of the current billing cycle, at which time
 it terminates the subscription. For example, if a user purchases a monthly
 subscription and cancels it on the 15th day of the cycle, Google Play will
 consider the subscription valid until the end of the 30th day (or other day,
@@ -357,12 +421,12 @@
 <p>If you receive requests for refunds, you can use the
 <a href="{@docRoot}google/play/billing/gp-purchase-status-api.html">Google Play
 Developer API</a> or the Merchant Center to cancel the subscription, verify that it
-is already cancelled, or refund the user's payment without cancelling it. You
+is already canceled, or refund the user's payment without canceling it. You
 can also use the
 <a href="{@docRoot}google/play/billing/gp-purchase-status-api.html">Google
 Play Developer API</a> to <em>refund and revoke</em> a
 user's subscription. If you refund and revoke a subscription, the user's
-subscription is immediately cancelled, and the user's most recent subscription
+subscription is immediately canceled, and the user's most recent subscription
 payment is refunded. (If you want to refund more than the most recent payment,
 you can process additional refunds through the Merchant Center.)</p>
 
@@ -423,7 +487,7 @@
     <li>Remotely query the validity of a specific subscription at any time</li>
     <li>Cancel a subscription</li>
     <li>Defer a subscription's next billing date</li>
-    <li>Refund a subscription payment without cancelling the subscription</li>
+    <li>Refund a subscription payment without canceling the subscription</li>
     <li>Refund and revoke a subscription</li>
   </ul>
 
diff --git a/docs/html/google/play/billing/billing_testing.jd b/docs/html/google/play/billing/billing_testing.jd
index 36456cc..44b3286 100644
--- a/docs/html/google/play/billing/billing_testing.jd
+++ b/docs/html/google/play/billing/billing_testing.jd
@@ -25,8 +25,8 @@
 implementation:</p>
 
 <ul>
-<li>Test purchases, which let test account users make real purchase your published in-app items,
-but without any actual charges to the user accounts.</li>
+<li>Test purchases, which let license-test users purchase your published in-app
+    items, but without any actual charges to their accounts.</li>
 <li>Static billing responses from Google Play, for testing in early development</p>
 </ul>
 
@@ -43,14 +43,13 @@
 
 <p>When your In-app Billing implementation is ready, you can test purchasing of your in-app SKUs in two ways:</p>
 
-<ul>
-<li><strong>Test purchases</strong>, which let your selected license test users
-purchase your in-app products before the app is published, but without any
-resulting charges to the user, and </li>
+<ul> <li><strong>Test purchases</strong>, which let your selected license-test
+users purchase your in-app products without any resulting charges to the user.
+Test purchases can be used in alpha/beta releases or in published apps. </li>
 <li><strong>Real purchases</strong>, which let regular users make real purchases
 of your in-app products with actual charges to the user’s payment instruments.
-In this case, you can use Google Play’s alpha and beta release groups to manage
-the users who can make “live” purchases using your implementation.  </li>
+You can use Google Play’s alpha and beta release groups to manage
+the users who can make live purchases using your implementation.  </li>
 </ul>
 
 <p>The sections below provide more detail about how to use these approaches for
@@ -61,16 +60,21 @@
 <p>Test purchases offer a secure, convenient way to enable larger-scale testing
 of your In-app Billing implementation during development or in preparation for
 launch. They let authorized user accounts make purchases of your in-app products
-through Google Play while the app is still unpublished, without incurring any
-actual charges to the user accounts.</p>
+through Google Play without incurring any actual charges to the user
+accounts.</p>
 
-<p>Once authorized with testing access, those users can side-load your app and
-test the full merchandising, purchase, and fulfillment flow for your products.
+<p>Once authorized for testing access, those users can make purchases without
+being charged.
 Test purchases are real orders and Google Play processes them in the same way as
 other orders. When purchases are complete, Google Play prevents the orders from
 going to financial processing, ensuring that there are no actual charges to user
 accounts, and automatically canceling the completed orders after 14 days. </p>
 
+<p class="note">
+  <strong>Note:</strong> Test subscription purchases recur daily, regardless of
+  the product's subscription period.
+</p>
+
 <h4 id="setup">Setting up test purchases</h4>
 
 <p>It’s easy to set up test purchases&mdash;any user account can be chosen to be
@@ -91,14 +95,13 @@
 
 <p>Once you’ve added the users as license tester accounts and saved the change,
 within 15 minutes those users can begin making test purchases of your in-app
-products. You can then distribute your app to your testers and provide a means
-of getting feedback. </p>
+products.</p>
 
 <p class="note"><strong>Note</strong>: To make test purchases, the license test
 account must be on the user’s Android device. If the device has more than one
 account, the purchase will be made with the account that downloaded the app. If
 none of the accounts has downloaded the app, the purchase is made with the first
-account.Users can confirm the account that is making a purchase by expanding the
+account. Users can confirm the account that is making a purchase by expanding the
 purchase dialog.</p>
 
 <h4 id="tp-account">Test purchases and developer account</h4>
@@ -114,13 +117,13 @@
 with a notice across the center of the purchase dialog, for easy identification.
 </p>
 
-<h4 id="cancelling">Cancelling completed test purchases</h4>
+<h4 id="cancelling">Canceling completed test purchases</h4>
 <p>Google Play accumulates completed test purchases for each user but does not
 pass them on  to financial processing. Over time, it automatically clears out
-the purchases by cancelling them. </p>
+the purchases by canceling them. </p>
 
 <p>In some cases, you might want to manually cancel a test purchase to continue
-testing. For cancelling purchases, you have these options:</p>
+testing. For canceling purchases, you have these options:</p>
 
 <ul>
 <li>Wait for the transactions to expire&mdash;Google Play clears completed test
@@ -130,13 +133,6 @@
 by looking up their order numbers.</li>
 </ul>
 
-<h4 id="requirements">Requirements for using test purchases</h4>
-<p>If you plan to use test purchases, please note the requirements and limitations below: </p>
-<ul>
-<li>Test purchases is only supported for license test accounts when the app is using the In-app Billing v3 API.</li>
-<li>Test purchases are only supported for in-app products, not for in-app subscriptions.</li>
-</ul>
-
 <h3 id="transations">Testing with real transactions</h3>
 <p>As you prepare to launch an app that uses In-app Billing, you can make use of
 Google Play alpha/beta release options to do validation and load testing on your
@@ -276,8 +272,8 @@
 href="{@docRoot}google/play/billing/billing_admin.html#billing-testing-setup">Setting up test
 accounts</a>.</p>
 
-<p>Also, a test account can purchase an item in your product list only if the item is published. The
-application does not need to be published, but the item does need to be published.</p>
+<p>A test account can purchase an item in your product list only if the
+item is published.</p>
 
 <p>To test your In-app Billing implementation with actual purchases, follow these steps:</p>
 
diff --git a/docs/html/google/play/billing/index.jd b/docs/html/google/play/billing/index.jd
index bdbf5c7..47620c8 100644
--- a/docs/html/google/play/billing/index.jd
+++ b/docs/html/google/play/billing/index.jd
@@ -14,6 +14,16 @@
 <div class="sidebox">
   <h2><strong>New in In-App Billing</strong></h2>
   <ul>
+  <li><strong>Subscription Upgrade/Downgrade</strong>&mdash;A user can
+    subscribe to a higher or lower tier of subscription while their current
+    subscription is active. The old subscription is canceled, and the unused
+    portion is applied on a pro-rated basis to the new subscription.</li>
+  <li><strong>Manual Subscription Renewal</strong>&mdash;A user can purchase
+    a subscription at the current rate while their existing subscription is
+    still active. The existing subscription is extended by the appropriate
+    period.</li>
+  <li><strong>IAB Sandbox</strong>&mdash;The In-app Billing Sandbox now supports
+    testing subscription purchases.</li>
   <li><strong>IAB v2 shutdown</strong>&mdash;In-app Billing v2 API is deprecated and will be shut down in January 2015. If your app is still using In-app Billing v2, please migrate to the v3 API as soon as possible.</li>
   <li><strong>Seasonal subscriptions</strong>&mdash;You can now set up a
     recurring <a href="billing_subscriptions.html#user-billing">seasonal
@@ -35,7 +45,6 @@
     subscription ends
     immediately, and his or her most recent subscription payment is
     refunded.</li>
-  <li><strong>In-app Billing Version 3</strong>&mdash;The <a href="{@docRoot}google/play/billing/api.html">latest version</a> of In-app Billing features a synchronous API that is easier to implement and lets you manage in-app products and subscriptions more effectively.</li>
  </ul>
 </div>
 </div>
diff --git a/docs/html/google/play/billing/versions.jd b/docs/html/google/play/billing/versions.jd
index dbe3ea3..aa35501 100644
--- a/docs/html/google/play/billing/versions.jd
+++ b/docs/html/google/play/billing/versions.jd
@@ -11,10 +11,30 @@
 <p>At run time, your app can query the Google Play Store app to determine what version of the API it supports and what features are available. </p>
 
 <ul>
-<li>If you are using in-app  billing version 3, the version information is not directly returned the Google Play. Instead, you can check if Google Play supports the version of the In-app Billing API that you are using by sending a {@code isBillingSupported} request.</li>
+
+<li>If you are using in-app billing version 3 or later, the version information
+is not directly returned by Google Play. Instead, you can check if Google Play
+supports the version of the In-app Billing API that you are using by sending an
+{@code isBillingSupported} request.</li>
+
 <li>If the In-app Billing API version that you are using is earlier than version 3, the version information is returned in the <code>API_VERSION</code> key of the Bundle object passed in the {@code sendBillingRequest} method. For more information, see <a href="{@docRoot}google/play/billing/v2/billing_reference.html#billing-interface-v2">In-app Billing Service Interface</a>.</li>
 </ul>
 
+<h3 id="version_5">In-app Billing version 5</h3>
+<p><em>February 2015</em></p>
+<ul>
+<li>A user can manually extend an existing subscription. The subscription
+is extended by the appropriate amount of time.</li>
+<li>A user can upgrade or downgrade a subscription while it is active. The
+old subscription is canceled, and the unused portion is applied on a pro-rata
+basis to the new subscription.</li>
+</ul>
+
+<h3 id="version_4">In-app Billing version 4</h3>
+
+<p>Version 4 of the In-app Billing API did not introduce any public
+functionality.</p>
+
 <h3 id="version_3">In-app Billing version 3</h3>
 <p><em>February 2013</em></p>
 <ul>
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index 9caf938..127134f 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -56,6 +56,25 @@
       "distribute/googleplay/developer-console.html"
     ]
   },
+  "launch/static/ja": {
+    "title": "",
+    "resources": [
+      "https://www.youtube.com/watch?v=xelYnWcYkuE",
+      "https://www.youtube.com/playlist?list=PLCOC_kP3nqGIHEgwm9mybvA04Vn4Cg9nn",
+      "http://googledevjp.blogspot.jp/2014/12/android-wear.html",
+      "http://googledevjp.blogspot.jp/2014/12/android-studio-10.html",
+      "http://googledevjp.blogspot.jp/2014/12/google-play-65.html",
+      "intl/ja/distribute/googleplay/developer-console.html#alpha-beta",
+      "intl/ja/distribute/googleplay/guide.html",
+      "intl/ja/distribute/essentials/quality/core.html",
+      "http://support.google.com/googleplay/android-developer/answer/4430948?hl=ja",
+      "intl/ja/support.html",
+      "intl/ja/distribute/essentials/quality/wear.html",
+      "intl/ja/training/tv/start/index.html",
+      "http://googleforwork-japan.blogspot.jp/2014/12/gcp-google-cloud-platform-rpg-gcp.html",
+      "intl/ja/distribute/monetize/ads.html"
+    ]
+  },
   "distribute/gp/gplanding": {
     "resources": [
       "distribute/googleplay/about.html",
@@ -1203,4 +1222,4 @@
       "samples/BasicManagedProfile/index.html"
     ]
   }
-}
\ No newline at end of file
+}
diff --git a/docs/html/jd_extras.js b/docs/html/jd_extras.js
index e2a0539..288b614 100644
--- a/docs/html/jd_extras.js
+++ b/docs/html/jd_extras.js
@@ -1988,5 +1988,161 @@
     "keywords": ["analytics"],
     "type": "Guide",
     "titleFriendly": ""
+  },
+  {
+    "lang": "ja",
+    "title": "Gaming Everywhere",
+    "titleFriendly": "",
+    "summary": "東京ゲームショウ 2014 の基調講演より。",
+    "url": "https://www.youtube.com/watch?v=xelYnWcYkuE",
+    "group": "",
+    "keywords": [],
+    "tags": [],
+    "image": "http://img.youtube.com/vi/xelYnWcYkuE/hqdefault.jpg",
+    "type": "youtube"
+  },
+  {
+    "lang": "ja",
+    "title": "Playtime Tokyo",
+    "titleFriendly": "",
+    "summary": "アプリビジネスのノウハウを各担当者が講演しました。",
+    "url": "https://www.youtube.com/playlist?list=PLCOC_kP3nqGIHEgwm9mybvA04Vn4Cg9nn",
+    "group": "",
+    "keywords": [],
+    "tags": [],
+    "image": "http://img.youtube.com/vi/lJdjY3z6-LY/hqdefault.jpg",
+    "type": "youtube"
+  },
+  {
+    "lang": "ja",
+    "title": "Android Wear 関連の動画に日本語字幕が付きました",
+    "titleFriendly": "",
+    "summary": "",
+    "url": "http://googledevjp.blogspot.jp/2014/12/android-wear.html",
+    "group": "",
+    "keywords": [],
+    "tags": [],
+    "image": "http://i1.ytimg.com/vi/4JcDYkgqksY/maxresdefault.jpg",
+    "type": "blog"
+  },
+  {
+    "lang": "ja",
+    "title": "Android Studio 1.0 をリリースしました",
+    "titleFriendly": "",
+    "summary": "",
+    "url": "http://googledevjp.blogspot.jp/2014/12/android-studio-10.html",
+    "group": "",
+    "keywords": [],
+    "tags": [],
+    "image": "http://3.bp.blogspot.com/-1hV3sD1At74/VIaQSWBasUI/AAAAAAAABAU/9vYLJMsmMuQ/s1600/studio-logo.png",
+    "type": "blog"
+  },
+  {
+    "lang": "ja",
+    "title": "Google Play 開発者サービス 6.5 のご紹介",
+    "titleFriendly": "",
+    "summary": "",
+    "url": "http://googledevjp.blogspot.jp/2014/12/google-play-65.html",
+    "group": "",
+    "keywords": [],
+    "tags": [],
+    "image": "http://1.bp.blogspot.com/-4BNREC0Jojo/VGo7ahW35wI/AAAAAAAABAc/9thZl94F6fY/s1600/GMS%2B-%2BRelease%2BBlog%2BNacho%2B-%2BMap%2BToolbar.png",
+    "type": "blog"
+  },
+  {
+    "lang": "ja",
+    "title": "Alpha and Beta Testing",
+    "titleFriendly": "",
+    "summary": "アプリのローンチにまつわるリスクを最小限にするために必須のツールです。[英語コンテンツ]",
+    "url": "intl/ja/distribute/googleplay/developer-console.html#alpha-beta",
+    "group": "",
+    "keywords": [],
+    "tags": [],
+    "image": "images/gp-dc-ab.png",
+    "type": "distribute"
+  },
+  {
+    "lang": "ja",
+    "title": "Finding Success on Google Play",
+    "titleFriendly": "",
+    "summary": "Google Play での成功の秘訣がこの一冊に。[英語コンテンツ]",
+    "url": "intl/ja/distribute/googleplay/guide.html",
+    "group": "",
+    "keywords": [],
+    "tags": [],
+    "image": "distribute/images/play_dev_guide_b.jpg",
+    "type": "distribute"
+  },
+  {
+    "lang": "ja",
+    "title": "Core App Quality",
+    "titleFriendly": "",
+    "summary": "",
+    "url": "intl/ja/distribute/essentials/quality/core.html",
+    "group": "",
+    "keywords": [],
+    "tags": [],
+    "image": "images/gp-core-quality.png",
+    "type": "distribute"
+  },
+  {
+    "lang": "ja",
+    "title": "Google Play アプリ ポリシー センター",
+    "titleFriendly": "",
+    "summary": "",
+    "url": "http://support.google.com/googleplay/android-developer/answer/4430948?hl=ja",
+    "group": "",
+    "keywords": [],
+    "tags": [],
+    "image": "https://storage.googleapis.com/support-kms-prod/SNP_712EA2784949DDF085C46E3BE7B1DC618A09_4389356_en_v0",
+    "type": "distribute"
+  },
+  {
+    "lang": "ja",
+    "title": "Developer Support",
+    "titleFriendly": "",
+    "summary": "",
+    "url": "intl/ja/support.html",
+    "group": "",
+    "keywords": [],
+    "tags": [],
+    "image": "",
+    "type": "distribute"
+  },
+  {
+    "lang": "ja",
+    "title": "Wear App Quality",
+    "titleFriendly": "",
+    "summary": "いよいよウェアラブルの時代が到来。[英語コンテンツ]",
+    "url": "intl/ja/distribute/essentials/quality/wear.html",
+    "group": "",
+    "keywords": [],
+    "tags": [],
+    "image": "distribute/images/gp-wear-quality.png",
+    "type": "distribute"
+  },
+  {
+    "lang": "ja",
+    "title": "Google Cloud Platform が支える、新感覚リアルタイム RPG ユニゾンリーグ - 株式会社エイチームの GCP 導入事例",
+    "titleFriendly": "",
+    "summary": "スケーラブルなバックエンドを実現する Google Cloud Platform の最新導入事例。",
+    "url": "http://googleforwork-japan.blogspot.jp/2014/12/gcp-google-cloud-platform-rpg-gcp.html",
+    "group": "",
+    "keywords": [],
+    "tags": [],
+    "image": "http://3.bp.blogspot.com/-xp7KoPkbne4/VI_PfoFil3I/AAAAAAAAA3U/-k1UZ0zjCBc/s1600/unison-league.jpeg",
+    "type": "distribute"
+  },
+  {
+    "lang": "ja",
+    "title": "Monetize with Ads",
+    "titleFriendly": "",
+    "summary": "アプリ内広告成功のコツがここに。[英語コンテンツ]",
+    "url": "intl/ja/distribute/monetize/ads.html",
+    "group": "",
+    "keywords": [],
+    "tags": [],
+    "image": "distribute/images/advertising.jpg",
+    "type": "distribute"
   }
 ]);
\ 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/wearables/apps/creating.jd b/docs/html/training/wearables/apps/creating.jd
index c12ffa7..487615b 100644
--- a/docs/html/training/wearables/apps/creating.jd
+++ b/docs/html/training/wearables/apps/creating.jd
@@ -106,6 +106,15 @@
   <li>Follow the app's instructions to pair your handheld with your wearable.
   This allows you to test out synced handheld notifications, if you're building them.</li>
   <li>Leave the Android Wear app open on your phone.</li>
+  <li>Enable adb debugging on the Android Wear device.</li>
+  <ol>
+    <li>Go to <strong>Settings > About</strong>.</li>
+    <li>Tap <strong>Build number</strong> seven times.</li>
+    <li>Swipe right to return to the Settings menu.</li>
+    <li>Go to <strong>Developer options</strong> at the bottom of the screen.
+    </li>
+    <li>Tap <strong>ADB Debugging</strong> to enable adb.</li>
+  </ol>
   <li>Connect the wearable to your machine through USB, so you can install apps directly to it
   as you develop. A message appears on both the wearable and the Android Wear app prompting you to allow debugging.</li>
   <p class="note"><strong>Note:</strong> If you can not connect your wearable to your machine via USB,
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/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index 4af5946..2c603e2 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -594,7 +594,7 @@
                 mTransitions.append(keyToFrom, pos | REVERSED_BIT | reversibleBit);
             }
 
-            return addChild(anim);
+            return pos;
         }
 
         int addStateSet(@NonNull int[] stateSet, @NonNull Drawable drawable, int id) {
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/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 98767a7..247f94a 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -39,7 +39,6 @@
 import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
-import android.util.IntProperty;
 import android.util.StateSet;
 import android.util.TypedValue;
 import android.util.Xml;
@@ -1372,20 +1371,5 @@
             default: return defaultMode;
         }
     }
-
-    /** @hide */
-    public static final IntProperty<Drawable> ALPHA = new IntProperty<Drawable>("alpha") {
-        @Override
-        public void setValue(Drawable object, int value) {
-            object.mutate();
-            object.setAlpha(value);
-            object.invalidateSelf();
-        }
-
-        @Override
-        public Integer get(Drawable object) {
-            return object.getAlpha();
-        }
-    };
 }
 
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index c4794d9..434134a 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -685,7 +685,7 @@
         DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
                 Resources res) {
             mOwner = owner;
-            mRes = res;
+            mRes = res != null ? res : orig != null ? orig.mRes : null;
 
             if (orig != null) {
                 mChangingConfigurations = orig.mChangingConfigurations;
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index aeef659..ca161ee 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -58,7 +58,7 @@
     private RotateState mState;
 
     /**
-     * Create a new rotating drawable with an empty state.
+     * Creates a new rotating drawable with no wrapped drawable.
      */
     public RotateDrawable() {
         this(new RotateState(null), null);
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/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index cca8a06..1963475 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -713,9 +713,7 @@
             mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
 
     virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
-        renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
-                mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
-                mPaint);
+        renderer.drawBitmap(mBitmap, mSrc, mLocalBounds, mPaint);
     }
 
     virtual void output(int level, uint32_t logFlags) const override {
@@ -1342,7 +1340,7 @@
             const Vector<OpStatePair>& ops, const Rect& bounds) override {
         for (unsigned int i = 0; i < ops.size(); i++) {
             const DeferredDisplayState& state = *(ops[i].state);
-            DrawOpMode drawOpMode = (i == ops.size() - 1) ? kDrawOpMode_Flush : kDrawOpMode_Defer;
+            DrawOpMode drawOpMode = (i == ops.size() - 1) ? DrawOpMode::kFlush : DrawOpMode::kDefer;
             renderer.restoreDisplayState(state, true); // restore all but the clip
 
             DrawTextOp& op = *((DrawTextOp*)ops[i].op);
@@ -1401,8 +1399,11 @@
     friend class DisplayListData; // grant DisplayListData access to info of child
 public:
     DrawRenderNodeOp(RenderNode* renderNode, int flags, const mat4& transformFromParent)
-            : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr),
-            mRenderNode(renderNode), mFlags(flags), mTransformFromParent(transformFromParent) {}
+            : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), nullptr)
+            , mRenderNode(renderNode)
+            , mFlags(flags)
+            , mTransformFromParent(transformFromParent)
+            , mSkipInOrderDraw(false) {}
 
     virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
             bool useQuickReject) override {
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 23181bc..2a673f4 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -258,7 +258,8 @@
         float srcRight, float srcBottom, float dstLeft, float dstTop,
         float dstRight, float dstBottom, const SkPaint* paint) {
     if (srcLeft == 0 && srcTop == 0
-            && srcRight == bitmap.width() && srcBottom == bitmap.height()
+            && srcRight == bitmap.width()
+            && srcBottom == bitmap.height()
             && (srcBottom - srcTop == dstBottom - dstTop)
             && (srcRight - srcLeft == dstRight - dstLeft)) {
         // transform simple rect to rect drawing case into position bitmap ops, since they merge
@@ -269,6 +270,30 @@
     } else {
         paint = refPaint(paint);
 
+        if (paint && paint->getShader()) {
+            float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft);
+            float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop);
+            if (!MathUtils::areEqual(scaleX, 1.0f) || !MathUtils::areEqual(scaleY, 1.0f)) {
+                // Apply the scale transform on the canvas, so that the shader
+                // effectively calculates positions relative to src rect space
+
+                save(SkCanvas::kMatrix_SaveFlag);
+                translate(dstLeft, dstTop);
+                scale(scaleX, scaleY);
+
+                dstLeft = 0.0f;
+                dstTop = 0.0f;
+                dstRight = srcRight - srcLeft;
+                dstBottom = srcBottom - srcTop;
+
+                addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(&bitmap),
+                        srcLeft, srcTop, srcRight, srcBottom,
+                        dstLeft, dstTop, dstRight, dstBottom, paint));
+                restore();
+                return;
+            }
+        }
+
         addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(&bitmap),
                 srcLeft, srcTop, srcRight, srcBottom,
                 dstLeft, dstTop, dstRight, dstBottom, paint));
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index bd0b3b7..8d519bb 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -30,7 +30,6 @@
 #include "DisplayList.h"
 #include "SkiaCanvasProxy.h"
 #include "RenderNode.h"
-#include "Renderer.h"
 #include "ResourceCache.h"
 
 namespace android {
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/Glop.h b/libs/hwui/Glop.h
index e500546..62da6e08 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -41,12 +41,13 @@
  * Position is always enabled by MeshState, these other attributes
  * are enabled/disabled dynamically based on mesh content.
  */
-enum VertexAttribFlags {
-    kNone_Attrib = 0,
-    kTextureCoord_Attrib = 1 << 0,
-    kColor_Attrib = 1 << 1,
-    kAlpha_Attrib = 1 << 2,
+enum class VertexAttribFlags {
+    kNone = 0,
+    kTextureCoord = 1 << 0,
+    kColor = 1 << 1,
+    kAlpha = 1 << 2,
 };
+MAKE_FLAGS_ENUM(VertexAttribFlags)
 
 /**
  * Structure containing all data required to issue an OpenGL draw
@@ -63,22 +64,28 @@
  */
 // TODO: PREVENT_COPY_AND_ASSIGN(...) or similar
 struct Glop {
-    /*
-     * Stores mesh - vertex and index data.
-     *
-     * buffer objects and void*s are mutually exclusive
-     * indices are optional, currently only GL_UNSIGNED_SHORT supported
-     */
     struct Mesh {
-        VertexAttribFlags vertexFlags;
         GLuint primitiveMode; // GL_TRIANGLES and GL_TRIANGLE_STRIP supported
-        GLuint vertexBufferObject;
-        GLuint indexBufferObject;
-        const void* vertices;
-        const void* indices;
-        GLvoid* texCoordOffset;
+
+        // buffer object and void* are mutually exclusive.
+        // Only GL_UNSIGNED_SHORT supported.
+        struct Indices {
+            GLuint bufferObject;
+            const void* indices;
+        } indices;
+
+        // buffer object and void*s are mutually exclusive.
+        // TODO: enforce mutual exclusion with restricted setters and/or unions
+        struct Vertices {
+            GLuint bufferObject;
+            VertexAttribFlags flags;
+            const void* position;
+            const void* texCoord;
+            const void* color;
+            GLsizei stride;
+        } vertices;
+
         int elementCount;
-        GLsizei stride;
         TextureVertex mappedVertices[4];
     } mesh;
 
@@ -87,8 +94,10 @@
 
         struct TextureData {
             Texture* texture;
+            GLenum target;
             GLenum filter;
             GLenum clamp;
+            Matrix4* textureTransform;
         } texture;
 
         bool colorEnabled;
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 4617588..3108a8d 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -32,7 +32,7 @@
 namespace uirenderer {
 
 #define TRIGGER_STAGE(stageFlag) \
-    LOG_ALWAYS_FATAL_IF(stageFlag & mStageFlags, "Stage %d cannot be run twice"); \
+    LOG_ALWAYS_FATAL_IF((stageFlag) & mStageFlags, "Stage %d cannot be run twice", (stageFlag)); \
     mStageFlags = static_cast<StageFlags>(mStageFlags | (stageFlag))
 
 #define REQUIRE_STAGES(requiredFlags) \
@@ -40,10 +40,10 @@
             "not prepared for current stage")
 
 static void setUnitQuadTextureCoords(Rect uvs, TextureVertex* quadVertex) {
-    TextureVertex::setUV(quadVertex++, uvs.left, uvs.top);
-    TextureVertex::setUV(quadVertex++, uvs.right, uvs.top);
-    TextureVertex::setUV(quadVertex++, uvs.left, uvs.bottom);
-    TextureVertex::setUV(quadVertex++, uvs.right, uvs.bottom);
+    quadVertex[0] = {0, 0, uvs.left, uvs.top};
+    quadVertex[1] = {1, 0, uvs.right, uvs.top};
+    quadVertex[2] = {0, 1, uvs.left, uvs.bottom};
+    quadVertex[3] = {1, 1, uvs.right, uvs.bottom};
 }
 
 GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop)
@@ -61,75 +61,95 @@
 GlopBuilder& GlopBuilder::setMeshUnitQuad() {
     TRIGGER_STAGE(kMeshStage);
 
-    mOutGlop->mesh.vertexFlags = kNone_Attrib;
     mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
-    mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
-    mOutGlop->mesh.vertices = nullptr;
-    mOutGlop->mesh.indexBufferObject = 0;
-    mOutGlop->mesh.indices = nullptr;
+    mOutGlop->mesh.indices = { 0, nullptr };
+    mOutGlop->mesh.vertices = {
+            mRenderState.meshState().getUnitQuadVBO(),
+            VertexAttribFlags::kNone,
+            nullptr, nullptr, nullptr,
+            kTextureVertexStride };
     mOutGlop->mesh.elementCount = 4;
-    mOutGlop->mesh.stride = kTextureVertexStride;
-    mOutGlop->mesh.texCoordOffset = nullptr;
     return *this;
 }
 
 GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper) {
+    if (uvMapper) {
+        // can't use unit quad VBO, so build UV vertices manually
+        return setMeshTexturedUvQuad(uvMapper, Rect(0, 0, 1, 1));
+    }
+
     TRIGGER_STAGE(kMeshStage);
 
-    mOutGlop->mesh.vertexFlags = kTextureCoord_Attrib;
     mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
-
-    if (CC_UNLIKELY(uvMapper)) {
-        Rect uvs(0, 0, 1, 1);
-        uvMapper->map(uvs);
-        setUnitQuadTextureCoords(uvs, &mOutGlop->mesh.mappedVertices[0]);
-
-        mOutGlop->mesh.vertexBufferObject = 0;
-        mOutGlop->mesh.vertices = &mOutGlop->mesh.mappedVertices[0];
-        mOutGlop->mesh.texCoordOffset = &mOutGlop->mesh.mappedVertices[0].u;
-    } else {
-        // standard UV coordinates, use regular unit quad VBO
-        mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
-        mOutGlop->mesh.vertices = nullptr;
-        mOutGlop->mesh.texCoordOffset = (GLvoid*) kMeshTextureOffset;
-    }
-    mOutGlop->mesh.indexBufferObject = 0;
-    mOutGlop->mesh.indices = nullptr;
+    mOutGlop->mesh.indices = { 0, nullptr };
+    mOutGlop->mesh.vertices = {
+            mRenderState.meshState().getUnitQuadVBO(),
+            VertexAttribFlags::kTextureCoord,
+            nullptr, (const void*) kMeshTextureOffset, nullptr,
+            kTextureVertexStride };
     mOutGlop->mesh.elementCount = 4;
-    mOutGlop->mesh.stride = kTextureVertexStride;
-    mDescription.hasTexture = true;
     return *this;
 }
 
-GlopBuilder& GlopBuilder::setMeshIndexedQuads(void* vertexData, int quadCount) {
+GlopBuilder& GlopBuilder::setMeshTexturedUvQuad(const UvMapper* uvMapper, Rect uvs) {
     TRIGGER_STAGE(kMeshStage);
 
-    mOutGlop->mesh.vertexFlags = kNone_Attrib;
-    mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
-    mOutGlop->mesh.vertexBufferObject = 0;
-    mOutGlop->mesh.vertices = vertexData;
-    mOutGlop->mesh.indexBufferObject = mRenderState.meshState().getQuadListIBO();
-    mOutGlop->mesh.indices = nullptr;
-    mOutGlop->mesh.texCoordOffset = nullptr;
-    mOutGlop->mesh.elementCount = 6 * quadCount;
-    mOutGlop->mesh.stride = kVertexStride;
+    if (CC_UNLIKELY(uvMapper)) {
+        uvMapper->map(uvs);
+    }
+    setUnitQuadTextureCoords(uvs, &mOutGlop->mesh.mappedVertices[0]);
 
+    const TextureVertex* textureVertex = mOutGlop->mesh.mappedVertices;
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+    mOutGlop->mesh.indices = { 0, nullptr };
+    mOutGlop->mesh.vertices = {
+            0,
+            VertexAttribFlags::kTextureCoord,
+            &textureVertex[0].x, &textureVertex[0].u, nullptr,
+            kTextureVertexStride };
+    mOutGlop->mesh.elementCount = 4;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshIndexedQuads(Vertex* vertexData, int quadCount) {
+    TRIGGER_STAGE(kMeshStage);
+
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
+    mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
+    mOutGlop->mesh.vertices = {
+            0,
+            VertexAttribFlags::kNone,
+            vertexData, nullptr, nullptr,
+            kVertexStride };
+    mOutGlop->mesh.elementCount = 6 * quadCount;
     return *this;
 }
 
 GlopBuilder& GlopBuilder::setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount) {
     TRIGGER_STAGE(kMeshStage);
 
-    mOutGlop->mesh.vertexFlags = kTextureCoord_Attrib;
     mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
-    mOutGlop->mesh.vertexBufferObject = 0;
-    mOutGlop->mesh.vertices = &vertexData[0].x;
-    mOutGlop->mesh.indexBufferObject = mRenderState.meshState().getQuadListIBO();
-    mOutGlop->mesh.indices = nullptr;
-    mOutGlop->mesh.texCoordOffset = &vertexData[0].u;
+    mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
+    mOutGlop->mesh.vertices = {
+            0,
+            VertexAttribFlags::kTextureCoord,
+            &vertexData[0].x, &vertexData[0].u, nullptr,
+            kTextureVertexStride };
     mOutGlop->mesh.elementCount = elementCount;
-    mOutGlop->mesh.stride = kTextureVertexStride;
-    mDescription.hasTexture = true;
+    return *this;
+}
+
+GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount) {
+    TRIGGER_STAGE(kMeshStage);
+
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
+    mOutGlop->mesh.indices = { 0, nullptr };
+    mOutGlop->mesh.vertices = {
+            0,
+            static_cast<VertexAttribFlags>(VertexAttribFlags::kTextureCoord | VertexAttribFlags::kColor),
+            &vertexData[0].x, &vertexData[0].u, &vertexData[0].r,
+            kColorTextureVertexStride };
+    mOutGlop->mesh.elementCount = elementCount;
     return *this;
 }
 
@@ -140,18 +160,17 @@
 
     bool alphaVertex = flags & VertexBuffer::kAlpha;
     bool indices = flags & VertexBuffer::kIndices;
-    mOutGlop->mesh.vertexFlags = alphaVertex ? kAlpha_Attrib : kNone_Attrib;
-    mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
-    mOutGlop->mesh.vertexBufferObject = 0;
-    mOutGlop->mesh.vertices = vertexBuffer.getBuffer();
-    mOutGlop->mesh.indexBufferObject = 0;
-    mOutGlop->mesh.indices = vertexBuffer.getIndices();
-    mOutGlop->mesh.texCoordOffset = nullptr;
-    mOutGlop->mesh.elementCount = indices
-            ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
-    mOutGlop->mesh.stride = alphaVertex ? kAlphaVertexStride : kVertexStride;
 
-    mDescription.hasVertexAlpha = alphaVertex;
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
+    mOutGlop->mesh.indices = { 0, vertexBuffer.getIndices() };
+    mOutGlop->mesh.vertices = {
+            0,
+            alphaVertex ? VertexAttribFlags::kAlpha : VertexAttribFlags::kNone,
+            vertexBuffer.getBuffer(), nullptr, nullptr,
+            alphaVertex ? kAlphaVertexStride : kVertexStride };
+    mOutGlop->mesh.elementCount = indices
+                ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
+
     mDescription.useShadowAlphaInterp = shadowInterp;
     return *this;
 }
@@ -182,7 +201,7 @@
 
     mOutGlop->blend = { GL_ZERO, GL_ZERO };
     if (mOutGlop->fill.color.a < 1.0f
-            || (mOutGlop->mesh.vertexFlags & kAlpha_Attrib)
+            || (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha)
             || (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend)
             || mOutGlop->roundRectClipState
             || PaintUtils::isBlendedShader(shader)
@@ -255,7 +274,8 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = { &texture, PaintUtils::getFilter(paint), GL_CLAMP_TO_EDGE };
+    mOutGlop->fill.texture = { &texture,
+            GL_TEXTURE_2D, PaintUtils::getFilter(paint), GL_CLAMP_TO_EDGE, nullptr };
 
     if (paint) {
         int color = paint->getColor();
@@ -273,7 +293,7 @@
 
         const bool SWAP_SRC_DST = false;
         if (alphaScale < 1.0f
-                || (mOutGlop->mesh.vertexFlags & kAlpha_Attrib)
+                || (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha)
                 || texture.blend
                 || mOutGlop->roundRectClipState) {
             Blend::getFactors(SkXfermode::kSrcOver_Mode, SWAP_SRC_DST,
@@ -296,7 +316,7 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM };
+    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
 
     setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
             paint.getShader(), paint.getColorFilter());
@@ -310,7 +330,7 @@
     REQUIRE_STAGES(kMeshStage);
 
     //specify invalid filter/clamp, since these are always static for PathTextures
-    mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM };
+    mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
 
     setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
             paint.getShader(), paint.getColorFilter());
@@ -326,7 +346,7 @@
     REQUIRE_STAGES(kMeshStage);
 
     //specify invalid filter/clamp, since these are always static for ShadowTextures
-    mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM };
+    mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
 
     const int ALPHA_BITMASK = SK_ColorBLACK;
     const int COLOR_BITMASK = ~ALPHA_BITMASK;
@@ -347,7 +367,7 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM };
+    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
     setFill(SK_ColorBLACK, 1.0f, SkXfermode::kSrcOver_Mode, nullptr, nullptr);
     return *this;
 }
@@ -356,7 +376,7 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM };
+    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
     setFill(SK_ColorBLACK, 1.0f, SkXfermode::kClear_Mode, nullptr, nullptr);
     return *this;
 }
@@ -366,7 +386,8 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = { &texture, GL_LINEAR, GL_CLAMP_TO_EDGE };
+    mOutGlop->fill.texture = { &texture,
+            GL_TEXTURE_2D, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr };
     mOutGlop->fill.color = { alpha, alpha, alpha, alpha };
 
     setFill(SK_ColorWHITE, alpha, mode, nullptr, colorFilter);
@@ -375,6 +396,21 @@
     return *this;
 }
 
+GlopBuilder& GlopBuilder::setFillTextureLayer(Layer& layer, float alpha) {
+    TRIGGER_STAGE(kFillStage);
+    REQUIRE_STAGES(kMeshStage);
+
+    mOutGlop->fill.texture = { &(layer.getTexture()),
+            layer.getRenderTarget(), GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() };
+    mOutGlop->fill.color = { alpha, alpha, alpha, alpha };
+
+    setFill(SK_ColorWHITE, alpha, layer.getMode(), nullptr, layer.getColorFilter());
+
+    mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+    mDescription.hasTextureTransform = true;
+    return *this;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Transform
 ////////////////////////////////////////////////////////////////////////////////
@@ -473,21 +509,33 @@
 
 void verify(const ProgramDescription& description, const Glop& glop) {
     bool hasTexture = glop.fill.texture.texture != nullptr;
-    LOG_ALWAYS_FATAL_IF(description.hasTexture != hasTexture);
-    LOG_ALWAYS_FATAL_IF((glop.mesh.vertexFlags & kTextureCoord_Attrib) != hasTexture);
+    LOG_ALWAYS_FATAL_IF(description.hasTexture && description.hasExternalTexture);
+    LOG_ALWAYS_FATAL_IF((description.hasTexture || description.hasExternalTexture )!= hasTexture);
+    LOG_ALWAYS_FATAL_IF((glop.mesh.vertices.flags & VertexAttribFlags::kTextureCoord) != hasTexture);
+
+    if ((glop.mesh.vertices.flags & VertexAttribFlags::kAlpha) && glop.mesh.vertices.bufferObject) {
+        LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible");
+    }
+
+    if (description.hasTextureTransform != (glop.fill.texture.textureTransform != nullptr)) {
+        LOG_ALWAYS_FATAL("Texture transform incorrectly specified");
+    }
 }
 
 void GlopBuilder::build() {
     REQUIRE_STAGES(kAllStages);
+    if (mOutGlop->mesh.vertices.flags & VertexAttribFlags::kTextureCoord) {
+        mDescription.hasTexture = mOutGlop->fill.texture.target == GL_TEXTURE_2D;
+        mDescription.hasExternalTexture = mOutGlop->fill.texture.target == GL_TEXTURE_EXTERNAL_OES;
+    }
+    mDescription.hasColors = mOutGlop->mesh.vertices.flags & VertexAttribFlags::kColor;
+    mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.flags & VertexAttribFlags::kAlpha;
 
     // serialize shader info into ShaderData
     GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0;
     SkiaShader::store(mCaches, mShader, mOutGlop->transform.modelView,
             &textureUnit, &mDescription, &(mOutGlop->fill.skiaShaderData));
 
-    mOutGlop->fill.program = mCaches.programCache.get(mDescription);
-    mOutGlop->transform.canvas.mapRect(mOutGlop->bounds);
-
     // duplicates ProgramCache's definition of color uniform presence
     const bool singleColor = !mDescription.hasTexture
             && !mDescription.hasExternalTexture
@@ -496,6 +544,10 @@
     mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor;
 
     verify(mDescription, *mOutGlop);
+
+    // Final step: populate program and map bounds into render target space
+    mOutGlop->fill.program = mCaches.programCache.get(mDescription);
+    mOutGlop->transform.canvas.mapRect(mOutGlop->bounds);
 }
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index cbdd0cd..4b871d5 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -40,8 +40,10 @@
 
     GlopBuilder& setMeshUnitQuad();
     GlopBuilder& setMeshTexturedUnitQuad(const UvMapper* uvMapper);
+    GlopBuilder& setMeshTexturedUvQuad(const UvMapper* uvMapper, const Rect uvs);
     GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp);
-    GlopBuilder& setMeshIndexedQuads(void* vertexData, int quadCount);
+    GlopBuilder& setMeshIndexedQuads(Vertex* vertexData, int quadCount);
+    GlopBuilder& setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount);
     GlopBuilder& setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount); // TODO: take quadCount
 
     GlopBuilder& setFillPaint(const SkPaint& paint, float alphaScale);
@@ -55,11 +57,19 @@
     GlopBuilder& setFillClear();
     GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
             float alpha, SkXfermode::Mode mode);
+    GlopBuilder& setFillTextureLayer(Layer& layer, float alpha);
 
     GlopBuilder& setTransform(const Matrix4& ortho, const Matrix4& transform, bool fudgingOffset);
 
     GlopBuilder& setModelViewMapUnitToRect(const Rect destination);
     GlopBuilder& setModelViewMapUnitToRectSnap(const Rect destination);
+    GlopBuilder& setModelViewMapUnitToRectOptionalSnap(bool snap, const Rect destination) {
+        if (snap) {
+            return setModelViewMapUnitToRectSnap(destination);
+        } else {
+            return setModelViewMapUnitToRect(destination);
+        }
+    }
     GlopBuilder& setModelViewOffsetRect(float offsetX, float offsetY, const Rect source);
     GlopBuilder& setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source);
 
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index f598664..30ffcea 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -356,8 +356,9 @@
 
 bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap) {
     Caches& caches = Caches::getInstance();
-    if (layer && bitmap->width() <= caches.maxTextureSize &&
-            bitmap->height() <= caches.maxTextureSize) {
+    if (layer
+            && bitmap->width() <= caches.maxTextureSize
+            && bitmap->height() <= caches.maxTextureSize) {
 
         GLuint fbo = caches.fboCache.get();
         if (!fbo) {
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b62af3b..83715ba 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -846,8 +846,21 @@
 }
 
 void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
-    float alpha = getLayerAlpha(layer);
+    if (USE_GLOPS) {
+        bool snap = !layer->getForceFilter()
+                && layer->getWidth() == (uint32_t) rect.getWidth()
+                && layer->getHeight() == (uint32_t) rect.getHeight();
+        Glop glop;
+        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+        aBuilder.setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
+                .setFillTextureLayer(*layer, getLayerAlpha(layer))
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewMapUnitToRectOptionalSnap(snap, rect)
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+    }
 
+    float alpha = getLayerAlpha(layer);
     setupDraw();
     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
         setupDrawWithTexture();
@@ -866,10 +879,10 @@
     } else {
         setupDrawExternalTexture(layer->getTextureId());
     }
-    if (currentTransform()->isPureTranslate() &&
-            !layer->getForceFilter() &&
-            layer->getWidth() == (uint32_t) rect.getWidth() &&
-            layer->getHeight() == (uint32_t) rect.getHeight()) {
+    if (currentTransform()->isPureTranslate()
+            && !layer->getForceFilter()
+            && layer->getWidth() == (uint32_t) rect.getWidth()
+            && layer->getHeight() == (uint32_t) rect.getHeight()) {
         const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
         const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
 
@@ -1234,7 +1247,7 @@
             aBuilder.setMeshIndexedQuads(&mesh[0], quadCount)
                     .setFillClear()
                     .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
-                    .setModelViewOffsetRect(0, 0, currentSnapshot()->getClipRect())
+                    .setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getClipRect()))
                     .setRoundRectClipState(currentSnapshot()->roundRectClipState)
                     .build();
             renderGlop(glop);
@@ -2077,17 +2090,14 @@
         return;
     }
 
-    // TODO: use quickReject on bounds from vertices
-    mRenderState.scissor().setEnabled(true);
-
     float left = FLT_MAX;
     float top = FLT_MAX;
     float right = FLT_MIN;
     float bottom = FLT_MIN;
 
-    const uint32_t count = meshWidth * meshHeight * 6;
+    const uint32_t elementCount = meshWidth * meshHeight * 6;
 
-    std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[count]);
+    std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]);
     ColorTextureVertex* vertex = &mesh[0];
 
     std::unique_ptr<int[]> tempColors;
@@ -2098,7 +2108,6 @@
         colors = tempColors.get();
     }
 
-    mCaches.textureState().activateTexture(0);
     Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
     const UvMapper& mapper(getMapper(texture));
 
@@ -2149,6 +2158,25 @@
     }
     const AutoTexture autoCleanup(texture);
 
+    if (USE_GLOPS) {
+        /*
+         * TODO: handle alpha_8 textures correctly by applying paint color, but *not*
+         * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh.
+         */
+        bool isAlpha8Texture = false;
+        Glop glop;
+        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+        aBuilder.setMeshColoredTexturedMesh(mesh.get(), elementCount)
+                .setFillTexturePaint(*texture, isAlpha8Texture, paint, currentSnapshot()->alpha)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
+    mCaches.textureState().activateTexture(0);
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
     texture->setFilter(PaintUtils::getFilter(paint), true);
 
@@ -2156,12 +2184,10 @@
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
+
+    dirtyLayer(left, top, right, bottom, *currentTransform());
+
     float a = alpha / 255.0f;
-
-    if (hasLayer()) {
-        dirtyLayer(left, top, right, bottom, *currentTransform());
-    }
-
     setupDraw();
     setupDrawWithTextureAndColor();
     setupDrawColor(a, a, a, a);
@@ -2175,7 +2201,7 @@
     setupDrawColorFilterUniforms(getColorFilter(paint));
     setupDrawMesh(&mesh[0].x, &mesh[0].u, &mesh[0].r);
 
-    glDrawArrays(GL_TRIANGLES, 0, count);
+    glDrawArrays(GL_TRIANGLES, 0, elementCount);
 
     int slot = mCaches.program().getAttrib("colors");
     if (slot >= 0) {
@@ -2185,26 +2211,43 @@
     mDirty = true;
 }
 
-void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap,
-         float srcLeft, float srcTop, float srcRight, float srcBottom,
-         float dstLeft, float dstTop, float dstRight, float dstBottom,
-         const SkPaint* paint) {
-    if (quickRejectSetupScissor(dstLeft, dstTop, dstRight, dstBottom)) {
+void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, const SkPaint* paint) {
+    if (quickRejectSetupScissor(dst)) {
         return;
     }
 
-    mCaches.textureState().activateTexture(0);
     Texture* texture = getTexture(bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
+    if (USE_GLOPS) {
+        Rect uv(fmax(0.0f, src.left / texture->width),
+                fmax(0.0f, src.top / texture->height),
+                fmin(1.0f, src.right / texture->width),
+                fmin(1.0f, src.bottom / texture->height));
+
+        bool isAlpha8Texture = bitmap->colorType() == kAlpha_8_SkColorType;
+        Glop glop;
+        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+        aBuilder.setMeshTexturedUvQuad(texture->uvMapper, uv)
+                .setFillTexturePaint(*texture, isAlpha8Texture, paint, currentSnapshot()->alpha)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewMapUnitToRectSnap(dst)
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
+    mCaches.textureState().activateTexture(0);
+
     const float width = texture->width;
     const float height = texture->height;
 
-    float u1 = fmax(0.0f, srcLeft / width);
-    float v1 = fmax(0.0f, srcTop / height);
-    float u2 = fmin(1.0f, srcRight / width);
-    float v2 = fmin(1.0f, srcBottom / height);
+    float u1 = fmax(0.0f, src.left / width);
+    float v1 = fmax(0.0f, src.top / height);
+    float u2 = fmin(1.0f, src.right / width);
+    float v2 = fmin(1.0f, src.bottom / height);
 
     getMapper(texture).map(u1, v1, u2, v2);
 
@@ -2213,25 +2256,21 @@
 
     texture->setWrap(GL_CLAMP_TO_EDGE, true);
 
-    float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft);
-    float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop);
+    float scaleX = (dst.right - dst.left) / (src.right - src.left);
+    float scaleY = (dst.bottom - dst.top) / (src.bottom - src.top);
 
     bool scaled = scaleX != 1.0f || scaleY != 1.0f;
-    // Apply a scale transform on the canvas only when a shader is in use
-    // Skia handles the ratio between the dst and src rects as a scale factor
-    // when a shader is set
-    bool useScaleTransform = getShader(paint) && scaled;
     bool ignoreTransform = false;
 
-    if (CC_LIKELY(currentTransform()->isPureTranslate() && !useScaleTransform)) {
-        float x = (int) floorf(dstLeft + currentTransform()->getTranslateX() + 0.5f);
-        float y = (int) floorf(dstTop + currentTransform()->getTranslateY() + 0.5f);
+    if (CC_LIKELY(currentTransform()->isPureTranslate())) {
+        float x = (int) floorf(dst.left + currentTransform()->getTranslateX() + 0.5f);
+        float y = (int) floorf(dst.top + currentTransform()->getTranslateY() + 0.5f);
 
-        dstRight = x + (dstRight - dstLeft);
-        dstBottom = y + (dstBottom - dstTop);
+        dst.right = x + (dst.right - dst.left);
+        dst.bottom = y + (dst.bottom - dst.top);
 
-        dstLeft = x;
-        dstTop = y;
+        dst.left = x;
+        dst.top = y;
 
         texture->setFilter(scaled ? PaintUtils::getFilter(paint) : GL_NEAREST, true);
         ignoreTransform = true;
@@ -2239,34 +2278,18 @@
         texture->setFilter(PaintUtils::getFilter(paint), true);
     }
 
-    if (CC_UNLIKELY(useScaleTransform)) {
-        save(SkCanvas::kMatrix_SaveFlag);
-        translate(dstLeft, dstTop);
-        scale(scaleX, scaleY);
-
-        dstLeft = 0.0f;
-        dstTop = 0.0f;
-
-        dstRight = srcRight - srcLeft;
-        dstBottom = srcBottom - srcTop;
-    }
-
     if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
-        drawAlpha8TextureMesh(dstLeft, dstTop, dstRight, dstBottom,
+        drawAlpha8TextureMesh(dst.left, dst.top, dst.right, dst.bottom,
                 texture->id, paint,
                 &mMeshVertices[0].x, &mMeshVertices[0].u,
                 GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
     } else {
-        drawTextureMesh(dstLeft, dstTop, dstRight, dstBottom,
+        drawTextureMesh(dst.left, dst.top, dst.right, dst.bottom,
                 texture->id, paint, texture->blend,
                 &mMeshVertices[0].x, &mMeshVertices[0].u,
                 GL_TRIANGLE_STRIP, kUnitQuadCount, false, ignoreTransform);
     }
 
-    if (CC_UNLIKELY(useScaleTransform)) {
-        restore();
-    }
-
     resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
 
     mDirty = true;
@@ -2877,7 +2900,7 @@
         const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
         DrawOpMode drawOpMode) {
 
-    if (drawOpMode == kDrawOpMode_Immediate) {
+    if (drawOpMode == DrawOpMode::kImmediate) {
         // The checks for corner-case ignorable text and quick rejection is only done for immediate
         // drawing as ops from DeferredDisplayList are already filtered for these
         if (text == nullptr || count == 0 || mState.currentlyIgnored() || canSkipText(paint) ||
@@ -2937,7 +2960,7 @@
     TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
 
     // don't call issuedrawcommand, do it at end of batch
-    bool forceFinish = (drawOpMode != kDrawOpMode_Defer);
+    bool forceFinish = (drawOpMode != DrawOpMode::kDefer);
     if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
         SkPaint paintCopy(*paint);
         paintCopy.setTextAlign(SkPaint::kLeft_Align);
@@ -2948,7 +2971,7 @@
                 positions, hasActiveLayer ? &layerBounds : nullptr, &functor, forceFinish);
     }
 
-    if ((status || drawOpMode != kDrawOpMode_Immediate) && hasActiveLayer) {
+    if ((status || drawOpMode != DrawOpMode::kImmediate) && hasActiveLayer) {
         if (!pureTranslate) {
             transform.mapRect(layerBounds);
         }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 851effa5..ae53313 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -17,6 +17,18 @@
 #ifndef ANDROID_HWUI_OPENGL_RENDERER_H
 #define ANDROID_HWUI_OPENGL_RENDERER_H
 
+#include "CanvasState.h"
+#include "Debug.h"
+#include "Extensions.h"
+#include "Matrix.h"
+#include "Program.h"
+#include "Rect.h"
+#include "Snapshot.h"
+#include "UvMapper.h"
+#include "Vertex.h"
+#include "Caches.h"
+#include "utils/PaintUtils.h"
+
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
@@ -38,24 +50,17 @@
 
 #include <androidfw/ResourceTypes.h>
 
-#include "CanvasState.h"
-#include "Debug.h"
-#include "Extensions.h"
-#include "Matrix.h"
-#include "Program.h"
-#include "Rect.h"
-#include "Renderer.h"
-#include "Snapshot.h"
-#include "UvMapper.h"
-#include "Vertex.h"
-#include "Caches.h"
-#include "utils/PaintUtils.h"
-
 class SkShader;
 
 namespace android {
 namespace uirenderer {
 
+enum class DrawOpMode {
+    kImmediate,
+    kDefer,
+    kFlush
+};
+
 class DeferredDisplayState;
 struct Glop;
 class RenderState;
@@ -118,23 +123,59 @@
 /**
  * OpenGL Renderer implementation.
  */
-class OpenGLRenderer : public Renderer, public CanvasStateClient {
+class OpenGLRenderer : public CanvasStateClient {
 public:
     OpenGLRenderer(RenderState& renderState);
     virtual ~OpenGLRenderer();
 
+    /**
+     * Sets the dimension of the underlying drawing surface. This method must
+     * be called at least once every time the drawing surface changes size.
+     *
+     * @param width The width in pixels of the underlysing surface
+     * @param height The height in pixels of the underlysing surface
+     */
+    void setViewport(int width, int height) { mState.setViewport(width, height); }
+
     void initProperties();
     void initLight(const Vector3& lightCenter, float lightRadius,
             uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
 
+    /*
+     * Prepares the renderer to draw a frame. This method must be invoked
+     * at the beginning of each frame. Only the specified rectangle of the
+     * frame is assumed to be dirty. A clip will automatically be set to
+     * the specified rectangle.
+     *
+     * @param opaque If true, the target surface is considered opaque
+     *               and will not be cleared. If false, the target surface
+     *               will be cleared
+     */
     virtual void prepareDirty(float left, float top, float right, float bottom,
-            bool opaque) override;
-    virtual void prepare(bool opaque) override {
+            bool opaque);
+
+    /**
+     * Prepares the renderer to draw a frame. This method must be invoked
+     * at the beginning of each frame. When this method is invoked, the
+     * entire drawing surface is assumed to be redrawn.
+     *
+     * @param opaque If true, the target surface is considered opaque
+     *               and will not be cleared. If false, the target surface
+     *               will be cleared
+     */
+    void prepare(bool opaque) {
         prepareDirty(0.0f, 0.0f, mState.getWidth(), mState.getHeight(), opaque);
     }
-    virtual bool finish() override;
 
-    virtual void callDrawGLFunction(Functor* functor, Rect& dirty) override;
+    /**
+     * Indicates the end of a frame. This method must be invoked whenever
+     * the caller is done rendering a frame.
+     * Returns true if any drawing was done during the frame (the output
+     * has changed / is "dirty" and should be displayed to the user).
+     */
+    virtual bool finish();
+
+    void callDrawGLFunction(Functor* functor, Rect& dirty);
 
     void pushLayerUpdate(Layer* layer);
     void cancelLayerUpdate(Layer* layer);
@@ -142,7 +183,7 @@
     void markLayersAsBuildLayers();
 
     virtual int saveLayer(float left, float top, float right, float bottom,
-            const SkPaint* paint, int flags) override {
+            const SkPaint* paint, int flags) {
         return saveLayer(left, top, right, bottom, paint, flags, nullptr);
     }
 
@@ -154,50 +195,48 @@
     int saveLayerDeferred(float left, float top, float right, float bottom,
             const SkPaint* paint, int flags);
 
-    virtual void drawRenderNode(RenderNode* displayList, Rect& dirty,
-            int32_t replayFlags = 1) override;
-    virtual void drawLayer(Layer* layer, float x, float y);
-    virtual void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) override;
+    void drawRenderNode(RenderNode* displayList, Rect& dirty, int32_t replayFlags = 1);
+    void drawLayer(Layer* layer, float x, float y);
+    void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
     void drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount,
             TextureVertex* vertices, bool pureTranslate, const Rect& bounds, const SkPaint* paint);
-    virtual void drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
-            float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, const SkPaint* paint) override;
-    virtual void drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
-            const float* vertices, const int* colors, const SkPaint* paint) override;
+    void drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst,
+            const SkPaint* paint);
+    void drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
+            const float* vertices, const int* colors, const SkPaint* paint);
     void drawPatches(const SkBitmap* bitmap, AssetAtlas::Entry* entry,
             TextureVertex* vertices, uint32_t indexCount, const SkPaint* paint);
-    virtual void drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
-            float left, float top, float right, float bottom, const SkPaint* paint) override;
+    void drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
+            float left, float top, float right, float bottom, const SkPaint* paint);
     void drawPatch(const SkBitmap* bitmap, const Patch* mesh, AssetAtlas::Entry* entry,
             float left, float top, float right, float bottom, const SkPaint* paint);
-    virtual void drawColor(int color, SkXfermode::Mode mode) override;
-    virtual void drawRect(float left, float top, float right, float bottom,
-            const SkPaint* paint) override;
-    virtual void drawRoundRect(float left, float top, float right, float bottom,
-            float rx, float ry, const SkPaint* paint) override;
-    virtual void drawCircle(float x, float y, float radius, const SkPaint* paint) override;
-    virtual void drawOval(float left, float top, float right, float bottom,
-            const SkPaint* paint) override;
-    virtual void drawArc(float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) override;
-    virtual void drawPath(const SkPath* path, const SkPaint* paint) override;
-    virtual void drawLines(const float* points, int count, const SkPaint* paint) override;
-    virtual void drawPoints(const float* points, int count, const SkPaint* paint) override;
-    virtual void drawTextOnPath(const char* text, int bytesCount, int count, const SkPath* path,
-            float hOffset, float vOffset, const SkPaint* paint) override;
-    virtual void drawPosText(const char* text, int bytesCount, int count,
-            const float* positions, const SkPaint* paint) override;
-    virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
+    void drawColor(int color, SkXfermode::Mode mode);
+    void drawRect(float left, float top, float right, float bottom,
+            const SkPaint* paint);
+    void drawRoundRect(float left, float top, float right, float bottom,
+            float rx, float ry, const SkPaint* paint);
+    void drawCircle(float x, float y, float radius, const SkPaint* paint);
+    void drawOval(float left, float top, float right, float bottom,
+            const SkPaint* paint);
+    void drawArc(float left, float top, float right, float bottom,
+            float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint);
+    void drawPath(const SkPath* path, const SkPaint* paint);
+    void drawLines(const float* points, int count, const SkPaint* paint);
+    void drawPoints(const float* points, int count, const SkPaint* paint);
+    void drawTextOnPath(const char* text, int bytesCount, int count, const SkPath* path,
+            float hOffset, float vOffset, const SkPaint* paint);
+    void drawPosText(const char* text, int bytesCount, int count,
+            const float* positions, const SkPaint* paint);
+    void drawText(const char* text, int bytesCount, int count, float x, float y,
             const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
-            DrawOpMode drawOpMode = kDrawOpMode_Immediate) override;
-    virtual void drawRects(const float* rects, int count, const SkPaint* paint) override;
+            DrawOpMode drawOpMode = DrawOpMode::kImmediate);
+    void drawRects(const float* rects, int count, const SkPaint* paint);
 
     void drawShadow(float casterAlpha,
             const VertexBuffer* ambientShadowVertexBuffer,
             const VertexBuffer* spotShadowVertexBuffer);
 
-    virtual void setDrawFilter(SkDrawFilter* filter) override;
+    void setDrawFilter(SkDrawFilter* filter);
 
     // If this value is set to < 1.0, it overrides alpha set on layer (see drawBitmap, drawLayer)
     void setOverrideLayerAlpha(float alpha) { mDrawModifiers.mOverrideLayerAlpha = alpha; }
@@ -340,36 +379,34 @@
     ///////////////////////////////////////////////////////////////////
     /// State manipulation
 
-    virtual void setViewport(int width, int height) override { mState.setViewport(width, height); }
+    int getSaveCount() const;
+    int save(int flags);
+    void restore();
+    void restoreToCount(int saveCount);
 
-    virtual int getSaveCount() const override;
-    virtual int save(int flags) override;
-    virtual void restore() override;
-    virtual void restoreToCount(int saveCount) override;
+    void getMatrix(SkMatrix* outMatrix) const { mState.getMatrix(outMatrix); }
+    void setMatrix(const SkMatrix& matrix) { mState.setMatrix(matrix); }
+    void concatMatrix(const SkMatrix& matrix) { mState.concatMatrix(matrix); }
 
-    virtual void getMatrix(SkMatrix* outMatrix) const override { mState.getMatrix(outMatrix); }
-    virtual void setMatrix(const SkMatrix& matrix) override { mState.setMatrix(matrix); }
-    virtual void concatMatrix(const SkMatrix& matrix) override { mState.concatMatrix(matrix); }
-
-    virtual void translate(float dx, float dy, float dz = 0.0f) override;
-    virtual void rotate(float degrees) override;
-    virtual void scale(float sx, float sy) override;
-    virtual void skew(float sx, float sy) override;
+    void translate(float dx, float dy, float dz = 0.0f);
+    void rotate(float degrees);
+    void scale(float sx, float sy);
+    void skew(float sx, float sy);
 
     void setMatrix(const Matrix4& matrix); // internal only convenience method
     void concatMatrix(const Matrix4& matrix); // internal only convenience method
 
-    virtual const Rect& getLocalClipBounds() const override { return mState.getLocalClipBounds(); }
+    const Rect& getLocalClipBounds() const { return mState.getLocalClipBounds(); }
     const Rect& getRenderTargetClipBounds() const { return mState.getRenderTargetClipBounds(); }
-    virtual bool quickRejectConservative(float left, float top,
-            float right, float bottom) const override {
+    bool quickRejectConservative(float left, float top,
+            float right, float bottom) const {
         return mState.quickRejectConservative(left, top, right, bottom);
     }
 
-    virtual bool clipRect(float left, float top,
-            float right, float bottom, SkRegion::Op op) override;
-    virtual bool clipPath(const SkPath* path, SkRegion::Op op) override;
-    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) override;
+    bool clipRect(float left, float top,
+            float right, float bottom, SkRegion::Op op);
+    bool clipPath(const SkPath* path, SkRegion::Op op);
+    bool clipRegion(const SkRegion* region, SkRegion::Op op);
 
     /**
      * Does not support different clipping Ops (that is, every call to setClippingOutline is
@@ -478,7 +515,6 @@
         return (mState.currentFlags() & Snapshot::kFlagFboTarget) && mState.currentRegion();
     }
 
-
     /**
      * Renders the specified layer as a textured quad.
      *
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
deleted file mode 100644
index 48d83b9..0000000
--- a/libs/hwui/Renderer.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_RENDERER_H
-#define ANDROID_HWUI_RENDERER_H
-
-#include <SkColorFilter.h>
-#include <SkPaint.h>
-#include <SkRegion.h>
-#include <utils/String8.h>
-
-#include "AssetAtlas.h"
-
-class SkDrawFilter;
-
-namespace android {
-
-class Functor;
-struct Res_png_9patch;
-
-namespace uirenderer {
-
-class RenderNode;
-class Layer;
-class Matrix4;
-class SkiaColorFilter;
-class Patch;
-
-enum DrawOpMode {
-    kDrawOpMode_Immediate,
-    kDrawOpMode_Defer,
-    kDrawOpMode_Flush
-};
-
-/**
- * Hwui's abstract version of Canvas.
- *
- * Provides methods for frame state operations, as well as the SkCanvas style transform/clip state,
- * and varied drawing operations.
- *
- * Should at some point interact with native SkCanvas.
- */
-class ANDROID_API Renderer {
-public:
-    virtual ~Renderer() {}
-
-// ----------------------------------------------------------------------------
-// Frame state operations
-// ----------------------------------------------------------------------------
-    /**
-     * Sets the dimension of the underlying drawing surface. This method must
-     * be called at least once every time the drawing surface changes size.
-     *
-     * @param width The width in pixels of the underlysing surface
-     * @param height The height in pixels of the underlysing surface
-     */
-    virtual void setViewport(int width, int height) = 0;
-
-    /**
-     * Prepares the renderer to draw a frame. This method must be invoked
-     * at the beginning of each frame. When this method is invoked, the
-     * entire drawing surface is assumed to be redrawn.
-     *
-     * @param opaque If true, the target surface is considered opaque
-     *               and will not be cleared. If false, the target surface
-     *               will be cleared
-     */
-    virtual void prepare(bool opaque) = 0;
-
-    /**
-     * Prepares the renderer to draw a frame. This method must be invoked
-     * at the beginning of each frame. Only the specified rectangle of the
-     * frame is assumed to be dirty. A clip will automatically be set to
-     * the specified rectangle.
-     *
-     * @param left The left coordinate of the dirty rectangle
-     * @param top The top coordinate of the dirty rectangle
-     * @param right The right coordinate of the dirty rectangle
-     * @param bottom The bottom coordinate of the dirty rectangle
-     * @param opaque If true, the target surface is considered opaque
-     *               and will not be cleared. If false, the target surface
-     *               will be cleared in the specified dirty rectangle
-     */
-    virtual void prepareDirty(float left, float top, float right, float bottom,
-            bool opaque) = 0;
-
-    /**
-     * Indicates the end of a frame. This method must be invoked whenever
-     * the caller is done rendering a frame.
-     * Returns true if any drawing was done during the frame (the output
-     * has changed / is "dirty" and should be displayed to the user).
-     */
-    virtual bool finish() = 0;
-
-// ----------------------------------------------------------------------------
-// Canvas state operations
-// ----------------------------------------------------------------------------
-    // Save (layer)
-    virtual int getSaveCount() const = 0;
-    virtual int save(int flags) = 0;
-    virtual void restore() = 0;
-    virtual void restoreToCount(int saveCount) = 0;
-
-    virtual int saveLayer(float left, float top, float right, float bottom,
-            const SkPaint* paint, int flags) = 0;
-
-    int saveLayerAlpha(float left, float top, float right, float bottom,
-            int alpha, int flags) {
-        SkPaint paint;
-        paint.setAlpha(alpha);
-        return saveLayer(left, top, right, bottom, &paint, flags);
-    }
-
-    // Matrix
-    virtual void getMatrix(SkMatrix* outMatrix) const = 0;
-    virtual void translate(float dx, float dy, float dz = 0.0f) = 0;
-    virtual void rotate(float degrees) = 0;
-    virtual void scale(float sx, float sy) = 0;
-    virtual void skew(float sx, float sy) = 0;
-
-    virtual void setMatrix(const SkMatrix& matrix) = 0;
-    virtual void concatMatrix(const SkMatrix& matrix) = 0;
-
-    // clip
-    virtual const Rect& getLocalClipBounds() const = 0;
-    virtual bool quickRejectConservative(float left, float top,
-            float right, float bottom) const = 0;
-    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op) = 0;
-    virtual bool clipPath(const SkPath* path, SkRegion::Op op) = 0;
-    virtual bool clipRegion(const SkRegion* region, SkRegion::Op op) = 0;
-
-    // Misc
-    virtual void setDrawFilter(SkDrawFilter* filter) = 0;
-
-// ----------------------------------------------------------------------------
-// Canvas draw operations
-// ----------------------------------------------------------------------------
-    virtual void drawColor(int color, SkXfermode::Mode mode) = 0;
-
-    // Bitmap-based
-    virtual void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) = 0;
-    virtual void drawBitmap(const SkBitmap* bitmap, float srcLeft, float srcTop,
-            float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, const SkPaint* paint) = 0;
-    virtual void drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
-            const float* vertices, const int* colors, const SkPaint* paint) = 0;
-    virtual void drawPatch(const SkBitmap* bitmap, const Res_png_9patch* patch,
-            float left, float top, float right, float bottom, const SkPaint* paint) = 0;
-
-    // Shapes
-    virtual void drawRect(float left, float top, float right, float bottom,
-            const SkPaint* paint) = 0;
-    virtual void drawRects(const float* rects, int count, const SkPaint* paint) = 0;
-    virtual void drawRoundRect(float left, float top, float right, float bottom,
-            float rx, float ry, const SkPaint* paint) = 0;
-    virtual void drawCircle(float x, float y, float radius, const SkPaint* paint) = 0;
-    virtual void drawOval(float left, float top, float right, float bottom,
-            const SkPaint* paint) = 0;
-    virtual void drawArc(float left, float top, float right, float bottom,
-            float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) = 0;
-    virtual void drawPath(const SkPath* path, const SkPaint* paint) = 0;
-    virtual void drawLines(const float* points, int count, const SkPaint* paint) = 0;
-    virtual void drawPoints(const float* points, int count, const SkPaint* paint) = 0;
-
-    // Text
-    virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
-            const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds,
-            DrawOpMode drawOpMode = kDrawOpMode_Immediate) = 0;
-    virtual void drawTextOnPath(const char* text, int bytesCount, int count, const SkPath* path,
-            float hOffset, float vOffset, const SkPaint* paint) = 0;
-    virtual void drawPosText(const char* text, int bytesCount, int count,
-            const float* positions, const SkPaint* paint) = 0;
-
-// ----------------------------------------------------------------------------
-// Canvas draw operations - special
-// ----------------------------------------------------------------------------
-    virtual void drawRenderNode(RenderNode* renderNode, Rect& dirty,
-            int32_t replayFlags) = 0;
-
-    // TODO: rename for consistency
-    virtual void callDrawGLFunction(Functor* functor, Rect& dirty) = 0;
-}; // class Renderer
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_RENDERER_H
diff --git a/libs/hwui/renderstate/MeshState.h b/libs/hwui/renderstate/MeshState.h
index 3c92ad8..e80f4d0 100644
--- a/libs/hwui/renderstate/MeshState.h
+++ b/libs/hwui/renderstate/MeshState.h
@@ -42,6 +42,7 @@
 const GLsizei kVertexStride = sizeof(Vertex);
 const GLsizei kAlphaVertexStride = sizeof(AlphaVertex);
 const GLsizei kTextureVertexStride = sizeof(TextureVertex);
+const GLsizei kColorTextureVertexStride = sizeof(ColorTextureVertex);
 
 const GLsizei kMeshTextureOffset = 2 * sizeof(float);
 const GLsizei kVertexAlphaOffset = 2 * sizeof(float);
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 192bf81..ca3a4c2 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -199,16 +199,10 @@
 // Render
 ///////////////////////////////////////////////////////////////////////////////
 
-/*
- * Not yet supported:
- *
- * Textures + coordinates
- * SkiaShader
- * RoundRect clipping
- */
-
 void RenderState::render(const Glop& glop) {
     const Glop::Mesh& mesh = glop.mesh;
+    const Glop::Mesh::Vertices& vertices = mesh.vertices;
+    const Glop::Mesh::Indices& indices = mesh.indices;
     const Glop::Fill& fill = glop.fill;
 
     // ---------------------------------------------
@@ -226,15 +220,15 @@
             glop.transform.fudgingOffset);
 
     // Color filter uniforms
-    if (glop.fill.filterMode == ProgramDescription::kColorBlend) {
-        const FloatColor& color = glop.fill.filter.color;
+    if (fill.filterMode == ProgramDescription::kColorBlend) {
+        const FloatColor& color = fill.filter.color;
         glUniform4f(mCaches->program().getUniform("colorBlend"),
                 color.r, color.g, color.b, color.a);
-    } else if (glop.fill.filterMode == ProgramDescription::kColorMatrix) {
+    } else if (fill.filterMode == ProgramDescription::kColorMatrix) {
         glUniformMatrix4fv(mCaches->program().getUniform("colorMatrix"), 1, GL_FALSE,
-                glop.fill.filter.matrix.matrix);
+                fill.filter.matrix.matrix);
         glUniform4fv(mCaches->program().getUniform("colorMatrixVector"), 1,
-                glop.fill.filter.matrix.vector);
+                fill.filter.matrix.vector);
     }
 
     // Round rect clipping uniforms
@@ -253,48 +247,57 @@
         glUniform1f(fill.program->getUniform("roundRectRadius"),
                 roundedOutRadius);
     }
+
     // --------------------------------
     // ---------- Mesh setup ----------
     // --------------------------------
     // vertices
-    const bool force = meshState().bindMeshBufferInternal(mesh.vertexBufferObject)
-            || (mesh.vertices != nullptr);
-    meshState().bindPositionVertexPointer(force, mesh.vertices, mesh.stride);
+    const bool force = meshState().bindMeshBufferInternal(vertices.bufferObject)
+            || (vertices.position != nullptr);
+    meshState().bindPositionVertexPointer(force, vertices.position, vertices.stride);
 
     // indices
-    meshState().bindIndicesBufferInternal(mesh.indexBufferObject);
+    meshState().bindIndicesBufferInternal(indices.bufferObject);
 
-    if (mesh.vertexFlags & kTextureCoord_Attrib) {
-        // glop.fill.texture always takes slot 0, shader samplers increment from there
+    if (vertices.flags & VertexAttribFlags::kTextureCoord) {
+        const Glop::Fill::TextureData& texture = fill.texture;
+        // texture always takes slot 0, shader samplers increment from there
         mCaches->textureState().activateTexture(0);
 
-        if (glop.fill.texture.clamp != GL_INVALID_ENUM) {
-            glop.fill.texture.texture->setWrap(glop.fill.texture.clamp, true);
+        if (texture.clamp != GL_INVALID_ENUM) {
+            texture.texture->setWrap(texture.clamp, true);
         }
-        if (glop.fill.texture.filter != GL_INVALID_ENUM) {
-            glop.fill.texture.texture->setFilter(glop.fill.texture.filter, true);
+        if (texture.filter != GL_INVALID_ENUM) {
+            texture.texture->setFilter(texture.filter, true);
         }
 
-        mCaches->textureState().bindTexture(fill.texture.texture->id);
+        mCaches->textureState().bindTexture(texture.target, texture.texture->id);
         meshState().enableTexCoordsVertexArray();
-        meshState().bindTexCoordsVertexPointer(force, mesh.texCoordOffset, mesh.stride);
+        meshState().bindTexCoordsVertexPointer(force, vertices.texCoord, vertices.stride);
+
+        if (texture.textureTransform) {
+            glUniformMatrix4fv(fill.program->getUniform("mainTextureTransform"), 1,
+                    GL_FALSE, &texture.textureTransform->data[0]);
+        }
     } else {
         meshState().disableTexCoordsVertexArray();
     }
-    if (mesh.vertexFlags & kColor_Attrib) {
-        LOG_ALWAYS_FATAL("color vertex attribute not yet supported");
-        // TODO: enable color attribute, disable when done
+    int colorLocation = -1;
+    if (vertices.flags & VertexAttribFlags::kColor) {
+        colorLocation = fill.program->getAttrib("colors");
+        glEnableVertexAttribArray(colorLocation);
+        glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, vertices.stride, vertices.color);
     }
-    int alphaSlot = -1;
-    if (mesh.vertexFlags & kAlpha_Attrib) {
-        const void* alphaCoords = ((const GLbyte*) glop.mesh.vertices) + kVertexAlphaOffset;
-        alphaSlot = fill.program->getAttrib("vtxAlpha");
-        glEnableVertexAttribArray(alphaSlot);
-        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
+    int alphaLocation = -1;
+    if (vertices.flags & VertexAttribFlags::kAlpha) {
+        // NOTE: alpha vertex position is computed assuming no VBO
+        const void* alphaCoords = ((const GLbyte*) vertices.position) + kVertexAlphaOffset;
+        alphaLocation = fill.program->getAttrib("vtxAlpha");
+        glEnableVertexAttribArray(alphaLocation);
+        glVertexAttribPointer(alphaLocation, 1, GL_FLOAT, GL_FALSE, vertices.stride, alphaCoords);
     }
-
     // Shader uniforms
-    SkiaShader::apply(*mCaches, glop.fill.skiaShaderData);
+    SkiaShader::apply(*mCaches, fill.skiaShaderData);
 
     // ------------------------------------
     // ---------- GL state setup ----------
@@ -304,27 +307,27 @@
     // ------------------------------------
     // ---------- Actual drawing ----------
     // ------------------------------------
-    if (mesh.indexBufferObject == meshState().getQuadListIBO()) {
+    if (indices.bufferObject == meshState().getQuadListIBO()) {
         // Since the indexed quad list is of limited length, we loop over
         // the glDrawXXX method while updating the vertex pointer
         GLsizei elementsCount = mesh.elementCount;
-        const GLbyte* vertices = static_cast<const GLbyte*>(mesh.vertices);
+        const GLbyte* vertexData = static_cast<const GLbyte*>(vertices.position);
         while (elementsCount > 0) {
             GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
 
             // rebind pointers without forcing, since initial bind handled above
-            meshState().bindPositionVertexPointer(false, vertices, mesh.stride);
-            if (mesh.vertexFlags & kTextureCoord_Attrib) {
+            meshState().bindPositionVertexPointer(false, vertexData, vertices.stride);
+            if (vertices.flags & VertexAttribFlags::kTextureCoord) {
                 meshState().bindTexCoordsVertexPointer(false,
-                        vertices + kMeshTextureOffset, mesh.stride);
+                        vertexData + kMeshTextureOffset, vertices.stride);
             }
 
             glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr);
             elementsCount -= drawCount;
-            vertices += (drawCount / 6) * 4 * mesh.stride;
+            vertexData += (drawCount / 6) * 4 * vertices.stride;
         }
-    } else if (mesh.indexBufferObject || mesh.indices) {
-        glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT, mesh.indices);
+    } else if (indices.bufferObject || indices.indices) {
+        glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT, indices.indices);
     } else {
         glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount);
     }
@@ -332,8 +335,11 @@
     // -----------------------------------
     // ---------- Mesh teardown ----------
     // -----------------------------------
-    if (glop.mesh.vertexFlags & kAlpha_Attrib) {
-        glDisableVertexAttribArray(alphaSlot);
+    if (vertices.flags & VertexAttribFlags::kAlpha) {
+        glDisableVertexAttribArray(alphaLocation);
+    }
+    if (vertices.flags & VertexAttribFlags::kColor) {
+        glDisableVertexAttribArray(colorLocation);
     }
 }
 
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/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h
index 49d364e7..2ed605e 100644
--- a/libs/hwui/utils/Macros.h
+++ b/libs/hwui/utils/Macros.h
@@ -41,6 +41,12 @@
         } \
         inline int operator&(int lhs, enumType rhs) { \
             return lhs & static_cast<int>(rhs); \
+        } \
+        inline int operator&(enumType lhs, int rhs) { \
+            return static_cast<int>(lhs) & rhs; \
+        } \
+        inline int operator&(enumType lhs, enumType rhs) { \
+            return static_cast<int>(lhs) & static_cast<int>(rhs); \
         }
 
 #endif /* MACROS_H */
diff --git a/packages/Keyguard/src/com/android/keyguard/CarrierText.java b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
index c023dc6..ca947af 100644
--- a/packages/Keyguard/src/com/android/keyguard/CarrierText.java
+++ b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
@@ -20,6 +20,8 @@
 import java.util.Locale;
 
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.TypedArray;
 import android.net.ConnectivityManager;
 import android.telephony.SubscriptionInfo;
@@ -33,6 +35,7 @@
 
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.IccCardConstants.State;
+import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.widget.LockPatternUtils;
 
 public class CarrierText extends TextView {
@@ -122,10 +125,27 @@
                         subs.get(0).getCarrierName());
             } else {
                 // We don't have a SubscriptionInfo to get the emergency calls only from.
-                // Lets just make it ourselves.
+                // Grab it from the old sticky broadcast if possible instead. We can use it
+                // here because no subscriptions are active, so we don't have
+                // to worry about MSIM clashing.
+                CharSequence text =
+                        getContext().getText(com.android.internal.R.string.emergency_calls_only);
+                Intent i = getContext().registerReceiver(null,
+                        new IntentFilter(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION));
+                if (i != null) {
+                    String spn = "";
+                    String plmn = "";
+                    if (i.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false)) {
+                        spn = i.getStringExtra(TelephonyIntents.EXTRA_SPN);
+                    }
+                    if (i.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false)) {
+                        plmn = i.getStringExtra(TelephonyIntents.EXTRA_PLMN);
+                    }
+                    if (DEBUG) Log.d(TAG, "Getting plmn/spn sticky brdcst " + plmn + "/" + spn);
+                    text = concatenate(plmn, spn);
+                }
                 displayText =  makeCarrierStringOnEmergencyCapable(
-                        getContext().getText(R.string.keyguard_missing_sim_message_short),
-                        getContext().getText(com.android.internal.R.string.emergency_calls_only));
+                        getContext().getText(R.string.keyguard_missing_sim_message_short), text);
             }
         }
         setText(displayText);
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 4c0cea8..d4aeab6 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -42,7 +42,8 @@
     <color name="qs_tile_divider">#29ffffff</color><!-- 16% white -->
     <color name="qs_tile_text">#B3FFFFFF</color><!-- 70% white -->
     <color name="qs_subhead">#99FFFFFF</color><!-- 60% white -->
-    <color name="qs_detail_empty">#24B0BEC5</color><!-- 14% blue grey 200-->
+    <color name="qs_detail_empty">#24B0BEC5</color><!-- 14% blue grey 200 -->
+    <color name="qs_detail_button">#FFB0BEC5</color><!-- 100% blue grey 200 -->
     <color name="qs_detail_transition">#66FFFFFF</color>
     <color name="qs_detail_progress_track">#99009688</color><!-- 60% deep teal 500 -->
     <color name="data_usage_secondary">#99FFFFFF</color><!-- 60% white -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index bf19b8d..94f77c6 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -145,6 +145,7 @@
 
     <style name="TextAppearance.QS.DetailButton">
         <item name="android:textSize">@dimen/qs_detail_button_text_size</item>
+        <item name="android:textColor">@color/qs_detail_button</item>
         <item name="android:textAllCaps">true</item>
         <item name="android:fontFamily">sans-serif-medium</item>
         <item name="android:gravity">center</item>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java
index 69a4932..602989a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ServiceMonitor.java
@@ -177,6 +177,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addDataScheme("package");
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
@@ -196,13 +197,14 @@
                 + " extras=" + bundleToString(intent.getExtras()));
         if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
             mHandler.sendEmptyMessage(MSG_START_SERVICE);
-        } else if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())) {
-            PackageManager pm = mContext.getPackageManager();
-            boolean serviceEnabled =
-                    pm.getApplicationEnabledSetting(mServiceName.getPackageName())
-                        != PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+        } else if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
+                || Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+            final PackageManager pm = mContext.getPackageManager();
+            final boolean serviceEnabled = isPackageAvailable()
+                    && pm.getApplicationEnabledSetting(mServiceName.getPackageName())
+                            != PackageManager.COMPONENT_ENABLED_STATE_DISABLED
                     && pm.getComponentEnabledSetting(mServiceName)
-                        != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+                            != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
             if (mBound && !serviceEnabled) {
                 stopService();
                 scheduleCheckBound();
@@ -289,4 +291,15 @@
         Settings.Secure.putStringForUser(mContext.getContentResolver(),
                 mSettingKey, setting, UserHandle.USER_CURRENT);
     }
+
+    public boolean isPackageAvailable() {
+        final ComponentName component = getComponent();
+        if (component == null) return false;
+        try {
+            return mContext.getPackageManager().isPackageAvailable(component.getPackageName());
+        } catch (RuntimeException e) {
+            Log.w(mTag, "Error checking package availability", e);
+            return false;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 5e3ec3f..f7f3bd8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -112,12 +112,12 @@
 
     private void setVolumeController(boolean register) {
         if (register) {
-            if (LOGD) Log.d(TAG, "Registering volume controller");
+            if (LOGD) Log.d(TAG, "Registering default volume controller");
             mAudioManager.setVolumeController(mVolumeController);
             mMediaSessionManager.setRemoteVolumeController(mRemoteVolumeController);
             DndTile.setVisible(mContext, false);
         } else {
-            if (LOGD) Log.d(TAG, "Unregistering volume controller");
+            if (LOGD) Log.d(TAG, "Unregistering default volume controller");
             mAudioManager.setVolumeController(null);
             mMediaSessionManager.setRemoteVolumeController(null);
         }
@@ -260,11 +260,16 @@
             if (LOGD) Log.d(TAG, "onNoService");
             setVolumeController(true);
             mRestorationNotification.hide();
+            if (!mVolumeControllerService.isPackageAvailable()) {
+                mVolumeControllerService.setComponent(null);
+            }
         }
 
         @Override
         public long onServiceStartAttempt() {
             if (LOGD) Log.d(TAG, "onServiceStartAttempt");
+            // poke the setting to update the uid
+            mVolumeControllerService.setComponent(mVolumeControllerService.getComponent());
             setVolumeController(false);
             mVolumeController.dismissNow();
             mRestorationNotification.show();
@@ -324,7 +329,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/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/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/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/policy/src/com/android/internal/policy/impl/BurnInProtectionHelper.java b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
similarity index 92%
rename from policy/src/com/android/internal/policy/impl/BurnInProtectionHelper.java
rename to services/core/java/com/android/server/policy/BurnInProtectionHelper.java
index 19fe262..b8a3155 100644
--- a/policy/src/com/android/internal/policy/impl/BurnInProtectionHelper.java
+++ b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
@@ -1,4 +1,20 @@
-package com.android.internal.policy.impl;
+/*
+ * 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;
@@ -9,9 +25,7 @@
 import android.content.res.Resources;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
-import android.os.Handler;
 import android.os.SystemClock;
-import android.util.Log;
 import android.view.Display;
 
 import com.android.server.LocalServices;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index af44833..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.
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/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/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 6dc54ce..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);
     }
 
@@ -5269,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/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index ef95a7b..bfb71c5 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -191,7 +191,7 @@
             statsOut.events.clear();
         }
 
-        statsOut.endTime = XmlUtils.readLongAttribute(parser, END_TIME_ATTR);
+        statsOut.endTime = statsOut.beginTime + XmlUtils.readLongAttribute(parser, END_TIME_ATTR);
 
         int eventCode;
         int outerDepth = parser.getDepth();
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 0aa8862..f869841 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -16,8 +16,6 @@
 
 package com.android.server.usb;
 
-import android.alsa.AlsaCardsParser;
-import android.alsa.AlsaDevicesParser;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
@@ -37,6 +35,8 @@
 import android.provider.Settings;
 import android.util.Slog;
 
+import com.android.internal.alsa.AlsaCardsParser;
+import com.android.internal.alsa.AlsaDevicesParser;
 import com.android.server.audio.AudioService;
 
 import libcore.io.IoUtils;
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/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index bcc1ccc4..9739d4e 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -77,6 +77,12 @@
             "android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
 
     /**
+     * The {@link android.content.Intent} action used to show the call accessibility settings page.
+     */
+    public static final String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS =
+            "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
+
+    /**
      * The {@link android.content.Intent} action used to show the call settings page.
      */
     public static final String ACTION_SHOW_CALL_SETTINGS =
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index ca3c636..37ffa06 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -62,7 +62,8 @@
     private CharSequence mDisplayName;
 
     /**
-     * The string displayed to the user that identifies Subscription Provider Name
+     * String that identifies SPN/PLMN
+     * TODO : Add a new field that identifies only SPN for a sim
      */
     private CharSequence mCarrierName;
 
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/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) {