Merge "Refactoring RecentsActivityValues into TaskDescription, and ensuring they are resolved when set. (Bug 14995928, 14832629)"
diff --git a/api/current.txt b/api/current.txt
index f204f21..b03c079 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -29,9 +29,8 @@
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
     field public static final java.lang.String BIND_ROUTE_PROVIDER = "android.permission.BIND_ROUTE_PROVIDER";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
-    field public static final java.lang.String BIND_TRUST_AGENT_SERVICE = "android.permission.BIND_TRUST_AGENT_SERVICE";
+    field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
-    field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
     field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
     field public static final java.lang.String BIND_WALLPAPER = "android.permission.BIND_WALLPAPER";
     field public static final java.lang.String BLUETOOTH = "android.permission.BLUETOOTH";
@@ -250,7 +249,7 @@
     field public static final int actionBarTabBarStyle = 16843508; // 0x10102f4
     field public static final int actionBarTabStyle = 16843507; // 0x10102f3
     field public static final int actionBarTabTextStyle = 16843509; // 0x10102f5
-    field public static final int actionBarTheme = 16843829; // 0x1010435
+    field public static final int actionBarTheme = 16843828; // 0x1010434
     field public static final int actionBarWidgetTheme = 16843671; // 0x1010397
     field public static final int actionButtonStyle = 16843480; // 0x10102d8
     field public static final int actionDropDownStyle = 16843479; // 0x10102d7
@@ -267,7 +266,7 @@
     field public static final int actionModeSplitBackground = 16843677; // 0x101039d
     field public static final int actionModeStyle = 16843668; // 0x1010394
     field public static final int actionOverflowButtonStyle = 16843510; // 0x10102f6
-    field public static final int actionOverflowMenuStyle = 16843849; // 0x1010449
+    field public static final int actionOverflowMenuStyle = 16843848; // 0x1010448
     field public static final int actionProviderClass = 16843657; // 0x1010389
     field public static final int actionViewClass = 16843516; // 0x10102fc
     field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
@@ -313,7 +312,7 @@
     field public static final int autoCompleteTextViewStyle = 16842859; // 0x101006b
     field public static final int autoLink = 16842928; // 0x10100b0
     field public static final int autoMirrored = 16843754; // 0x10103ea
-    field public static final int autoRemoveFromRecents = 16843851; // 0x101044b
+    field public static final int autoRemoveFromRecents = 16843850; // 0x101044a
     field public static final int autoStart = 16843445; // 0x10102b5
     field public static final deprecated int autoText = 16843114; // 0x101016a
     field public static final int autoUrlDetect = 16843404; // 0x101028c
@@ -382,27 +381,27 @@
     field public static final int clipChildren = 16842986; // 0x10100ea
     field public static final int clipOrientation = 16843274; // 0x101020a
     field public static final int clipToPadding = 16842987; // 0x10100eb
-    field public static final int clipToPath = 16843818; // 0x101042a
+    field public static final int clipToPath = 16843817; // 0x1010429
     field public static final int codes = 16843330; // 0x1010242
     field public static final int collapseColumns = 16843083; // 0x101014b
     field public static final int color = 16843173; // 0x10101a5
-    field public static final int colorAccent = 16843834; // 0x101043a
+    field public static final int colorAccent = 16843833; // 0x1010439
     field public static final int colorActivatedHighlight = 16843664; // 0x1010390
     field public static final int colorBackground = 16842801; // 0x1010031
     field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
-    field public static final int colorButtonNormal = 16843823; // 0x101042f
-    field public static final int colorButtonPressed = 16843824; // 0x1010430
-    field public static final int colorControlActivated = 16843822; // 0x101042e
-    field public static final int colorControlNormal = 16843821; // 0x101042d
+    field public static final int colorButtonNormal = 16843822; // 0x101042e
+    field public static final int colorButtonPressed = 16843823; // 0x101042f
+    field public static final int colorControlActivated = 16843821; // 0x101042d
+    field public static final int colorControlNormal = 16843820; // 0x101042c
     field public static final int colorFocusedHighlight = 16843663; // 0x101038f
     field public static final int colorForeground = 16842800; // 0x1010030
     field public static final int colorForegroundInverse = 16843270; // 0x1010206
     field public static final int colorLongPressedHighlight = 16843662; // 0x101038e
     field public static final int colorMultiSelectHighlight = 16843665; // 0x1010391
     field public static final int colorPressedHighlight = 16843661; // 0x101038d
-    field public static final int colorPrimary = 16843832; // 0x1010438
-    field public static final int colorPrimaryDark = 16843833; // 0x1010439
-    field public static final int colorPrimaryLight = 16843831; // 0x1010437
+    field public static final int colorPrimary = 16843831; // 0x1010437
+    field public static final int colorPrimaryDark = 16843832; // 0x1010438
+    field public static final int colorPrimaryLight = 16843830; // 0x1010436
     field public static final int columnCount = 16843639; // 0x1010377
     field public static final int columnDelay = 16843215; // 0x10101cf
     field public static final int columnOrderPreserved = 16843640; // 0x1010378
@@ -417,10 +416,14 @@
     field public static final int content = 16843355; // 0x101025b
     field public static final int contentAuthority = 16843408; // 0x1010290
     field public static final int contentDescription = 16843379; // 0x1010273
-    field public static final int controlX1 = 16843799; // 0x1010417
-    field public static final int controlX2 = 16843801; // 0x1010419
-    field public static final int controlY1 = 16843800; // 0x1010418
-    field public static final int controlY2 = 16843802; // 0x101041a
+    field public static final int contentInsetEnd = 16843863; // 0x1010457
+    field public static final int contentInsetLeft = 16843864; // 0x1010458
+    field public static final int contentInsetRight = 16843865; // 0x1010459
+    field public static final int contentInsetStart = 16843862; // 0x1010456
+    field public static final int controlX1 = 16843798; // 0x1010416
+    field public static final int controlX2 = 16843800; // 0x1010418
+    field public static final int controlY1 = 16843799; // 0x1010417
+    field public static final int controlY2 = 16843801; // 0x1010419
     field public static final int cropToPadding = 16843043; // 0x1010123
     field public static final int cursorVisible = 16843090; // 0x1010152
     field public static final int customNavigationLayout = 16843474; // 0x10102d2
@@ -461,7 +464,7 @@
     field public static final int dividerHorizontal = 16843564; // 0x101032c
     field public static final int dividerPadding = 16843562; // 0x101032a
     field public static final int dividerVertical = 16843530; // 0x101030a
-    field public static final int documentLaunchMode = 16843850; // 0x101044a
+    field public static final int documentLaunchMode = 16843849; // 0x1010449
     field public static final int drawSelectorOnTop = 16843004; // 0x10100fc
     field public static final int drawable = 16843161; // 0x1010199
     field public static final int drawableBottom = 16843118; // 0x101016e
@@ -490,7 +493,7 @@
     field public static final int editTextStyle = 16842862; // 0x101006e
     field public static final deprecated int editable = 16843115; // 0x101016b
     field public static final int editorExtras = 16843300; // 0x1010224
-    field public static final int elevation = 16843845; // 0x1010445
+    field public static final int elevation = 16843844; // 0x1010444
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
@@ -500,10 +503,10 @@
     field public static final int entries = 16842930; // 0x10100b2
     field public static final int entryValues = 16843256; // 0x10101f8
     field public static final int eventsInterceptionEnabled = 16843389; // 0x101027d
-    field public static final int excludeClass = 16843847; // 0x1010447
+    field public static final int excludeClass = 16843846; // 0x1010446
     field public static final int excludeFromRecents = 16842775; // 0x1010017
-    field public static final int excludeId = 16843846; // 0x1010446
-    field public static final int excludeViewName = 16843858; // 0x1010452
+    field public static final int excludeId = 16843845; // 0x1010445
+    field public static final int excludeViewName = 16843857; // 0x1010451
     field public static final int exitFadeDuration = 16843533; // 0x101030d
     field public static final int expandableListPreferredChildIndicatorLeft = 16842834; // 0x1010052
     field public static final int expandableListPreferredChildIndicatorRight = 16842835; // 0x1010053
@@ -528,15 +531,15 @@
     field public static final int fastScrollOverlayPosition = 16843578; // 0x101033a
     field public static final int fastScrollPreviewBackgroundLeft = 16843575; // 0x1010337
     field public static final int fastScrollPreviewBackgroundRight = 16843576; // 0x1010338
-    field public static final int fastScrollStyle = 16843794; // 0x1010412
+    field public static final int fastScrollStyle = 16843793; // 0x1010411
     field public static final int fastScrollTextColor = 16843609; // 0x1010359
     field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336
     field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339
-    field public static final int fill = 16843808; // 0x1010420
+    field public static final int fill = 16843807; // 0x101041f
     field public static final int fillAfter = 16843197; // 0x10101bd
     field public static final int fillBefore = 16843196; // 0x10101bc
     field public static final int fillEnabled = 16843343; // 0x101024f
-    field public static final int fillOpacity = 16843807; // 0x101041f
+    field public static final int fillOpacity = 16843806; // 0x101041e
     field public static final int fillViewport = 16843130; // 0x101017a
     field public static final int filter = 16843035; // 0x101011b
     field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
@@ -556,7 +559,6 @@
     field public static final int format12Hour = 16843722; // 0x10103ca
     field public static final int format24Hour = 16843723; // 0x10103cb
     field public static final int fragment = 16843491; // 0x10102e3
-    field public static final int fragmentBreadCrumbsStyle = 16843793; // 0x1010411
     field public static final int fragmentCloseEnterAnimation = 16843495; // 0x10102e7
     field public static final int fragmentCloseExitAnimation = 16843496; // 0x10102e8
     field public static final int fragmentFadeEnterAnimation = 16843497; // 0x10102e9
@@ -566,7 +568,7 @@
     field public static final int freezesText = 16843116; // 0x101016c
     field public static final int fromAlpha = 16843210; // 0x10101ca
     field public static final int fromDegrees = 16843187; // 0x10101b3
-    field public static final int fromId = 16843854; // 0x101044e
+    field public static final int fromId = 16843853; // 0x101044d
     field public static final int fromScene = 16843741; // 0x10103dd
     field public static final int fromXDelta = 16843206; // 0x10101c6
     field public static final int fromXScale = 16843202; // 0x10101c2
@@ -599,7 +601,7 @@
     field public static final int headerBackground = 16843055; // 0x101012f
     field public static final int headerDividersEnabled = 16843310; // 0x101022e
     field public static final int height = 16843093; // 0x1010155
-    field public static final int hideOnContentScroll = 16843848; // 0x1010448
+    field public static final int hideOnContentScroll = 16843847; // 0x1010447
     field public static final int hint = 16843088; // 0x1010150
     field public static final int homeAsUpIndicator = 16843531; // 0x101030b
     field public static final int homeLayout = 16843549; // 0x101031d
@@ -796,7 +798,7 @@
     field public static final int manageSpaceActivity = 16842756; // 0x1010004
     field public static final int mapViewStyle = 16842890; // 0x101008a
     field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
-    field public static final int matchOrder = 16843859; // 0x1010453
+    field public static final int matchOrder = 16843858; // 0x1010452
     field public static final int max = 16843062; // 0x1010136
     field public static final int maxDate = 16843584; // 0x1010340
     field public static final int maxEms = 16843095; // 0x1010157
@@ -829,9 +831,10 @@
     field public static final int moreIcon = 16843061; // 0x1010135
     field public static final int multiprocess = 16842771; // 0x1010013
     field public static final int name = 16842755; // 0x1010003
+    field public static final int navigationBarColor = 16843861; // 0x1010455
     field public static final int navigationMode = 16843471; // 0x10102cf
     field public static final int negativeButtonText = 16843254; // 0x10101f6
-    field public static final int nestedScrollingEnabled = 16843835; // 0x101043b
+    field public static final int nestedScrollingEnabled = 16843834; // 0x101043a
     field public static final int nextFocusDown = 16842980; // 0x10100e4
     field public static final int nextFocusForward = 16843580; // 0x101033c
     field public static final int nextFocusLeft = 16842977; // 0x10100e1
@@ -873,18 +876,18 @@
     field public static final int parentActivityName = 16843687; // 0x10103a7
     field public static final deprecated int password = 16843100; // 0x101015c
     field public static final int path = 16842794; // 0x101002a
-    field public static final int pathData = 16843809; // 0x1010421
+    field public static final int pathData = 16843808; // 0x1010420
     field public static final int pathPattern = 16842796; // 0x101002c
     field public static final int pathPrefix = 16842795; // 0x101002b
     field public static final int permission = 16842758; // 0x1010006
     field public static final int permissionFlags = 16843719; // 0x10103c7
     field public static final int permissionGroup = 16842762; // 0x101000a
     field public static final int permissionGroupFlags = 16843717; // 0x10103c5
-    field public static final int persistable = 16843825; // 0x1010431
+    field public static final int persistable = 16843824; // 0x1010430
     field public static final int persistent = 16842765; // 0x101000d
     field public static final int persistentDrawingCache = 16842990; // 0x10100ee
     field public static final deprecated int phoneNumber = 16843111; // 0x1010167
-    field public static final int pinned = 16843820; // 0x101042c
+    field public static final int pinned = 16843819; // 0x101042b
     field public static final int pivotX = 16843189; // 0x10101b5
     field public static final int pivotY = 16843190; // 0x10101b6
     field public static final int popupAnimationStyle = 16843465; // 0x10102c9
@@ -948,7 +951,7 @@
     field public static final int required = 16843406; // 0x101028e
     field public static final int requiredAccountType = 16843734; // 0x10103d6
     field public static final int requiredForAllUsers = 16843728; // 0x10103d0
-    field public static final int requiredForProfile = 16843819; // 0x101042b
+    field public static final int requiredForProfile = 16843818; // 0x101042a
     field public static final int requiresFadingEdge = 16843685; // 0x10103a5
     field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
     field public static final int resizeMode = 16843619; // 0x1010363
@@ -957,7 +960,7 @@
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
     field public static final int restrictedAccountType = 16843733; // 0x10103d5
-    field public static final int reversible = 16843855; // 0x101044f
+    field public static final int reversible = 16843854; // 0x101044e
     field public static final int right = 16843183; // 0x10101af
     field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
     field public static final int ringtoneType = 16843257; // 0x10101f9
@@ -1013,7 +1016,6 @@
     field public static final int selectableItemBackground = 16843534; // 0x101030e
     field public static final int selectedDateVerticalBar = 16843591; // 0x1010347
     field public static final int selectedWeekBackgroundColor = 16843586; // 0x1010342
-    field public static final int sessionService = 16843842; // 0x1010442
     field public static final int settingsActivity = 16843301; // 0x1010225
     field public static final int shadowColor = 16843105; // 0x1010161
     field public static final int shadowDx = 16843106; // 0x1010162
@@ -1034,7 +1036,7 @@
     field public static final int shrinkColumns = 16843082; // 0x101014a
     field public static final deprecated int singleLine = 16843101; // 0x101015d
     field public static final int singleUser = 16843711; // 0x10103bf
-    field public static final int slideEdge = 16843828; // 0x1010434
+    field public static final int slideEdge = 16843827; // 0x1010433
     field public static final int smallIcon = 16843422; // 0x101029e
     field public static final int smallScreens = 16843396; // 0x1010284
     field public static final int smoothScrollbar = 16843313; // 0x1010231
@@ -1046,19 +1048,19 @@
     field public static final int spinnerStyle = 16842881; // 0x1010081
     field public static final int spinnersShown = 16843595; // 0x101034b
     field public static final int splitMotionEvents = 16843503; // 0x10102ef
-    field public static final int splitTrack = 16843856; // 0x1010450
+    field public static final int splitTrack = 16843855; // 0x101044f
     field public static final int src = 16843033; // 0x1010119
     field public static final int ssp = 16843747; // 0x10103e3
     field public static final int sspPattern = 16843749; // 0x10103e5
     field public static final int sspPrefix = 16843748; // 0x10103e4
     field public static final int stackFromBottom = 16843005; // 0x10100fd
-    field public static final int stackViewStyle = 16843843; // 0x1010443
+    field public static final int stackViewStyle = 16843842; // 0x1010442
     field public static final int starStyle = 16842882; // 0x1010082
     field public static final int startColor = 16843165; // 0x101019d
     field public static final int startDelay = 16843746; // 0x10103e2
     field public static final int startOffset = 16843198; // 0x10101be
     field public static final deprecated int startYear = 16843132; // 0x101017c
-    field public static final int stateListAnimator = 16843852; // 0x101044c
+    field public static final int stateListAnimator = 16843851; // 0x101044b
     field public static final int stateNotNeeded = 16842774; // 0x1010016
     field public static final int state_above_anchor = 16842922; // 0x10100aa
     field public static final int state_accelerated = 16843547; // 0x101031b
@@ -1083,18 +1085,19 @@
     field public static final int state_single = 16842915; // 0x10100a3
     field public static final int state_window_focused = 16842909; // 0x101009d
     field public static final int staticWallpaperPreview = 16843569; // 0x1010331
+    field public static final int statusBarColor = 16843860; // 0x1010454
     field public static final int stepSize = 16843078; // 0x1010146
     field public static final int stopWithTask = 16843626; // 0x101036a
     field public static final int streamType = 16843273; // 0x1010209
     field public static final int stretchColumns = 16843081; // 0x1010149
     field public static final int stretchMode = 16843030; // 0x1010116
-    field public static final int stroke = 16843810; // 0x1010422
-    field public static final int strokeLineCap = 16843816; // 0x1010428
-    field public static final int strokeLineJoin = 16843817; // 0x1010429
-    field public static final int strokeOpacity = 16843811; // 0x1010423
-    field public static final int strokeWidth = 16843812; // 0x1010424
+    field public static final int stroke = 16843809; // 0x1010421
+    field public static final int strokeLineCap = 16843815; // 0x1010427
+    field public static final int strokeLineJoin = 16843816; // 0x1010428
+    field public static final int strokeOpacity = 16843810; // 0x1010422
+    field public static final int strokeWidth = 16843811; // 0x1010423
     field public static final int subtitle = 16843473; // 0x10102d1
-    field public static final int subtitleTextAppearance = 16843827; // 0x1010433
+    field public static final int subtitleTextAppearance = 16843826; // 0x1010432
     field public static final int subtitleTextStyle = 16843513; // 0x10102f9
     field public static final int subtypeExtraValue = 16843674; // 0x101039a
     field public static final int subtypeId = 16843713; // 0x10103c1
@@ -1111,7 +1114,7 @@
     field public static final int switchMinWidth = 16843632; // 0x1010370
     field public static final int switchPadding = 16843633; // 0x1010371
     field public static final int switchPreferenceStyle = 16843629; // 0x101036d
-    field public static final int switchStyle = 16843844; // 0x1010444
+    field public static final int switchStyle = 16843843; // 0x1010443
     field public static final int switchTextAppearance = 16843630; // 0x101036e
     field public static final int switchTextOff = 16843628; // 0x101036c
     field public static final int switchTextOn = 16843627; // 0x101036b
@@ -1127,7 +1130,7 @@
     field public static final int targetId = 16843740; // 0x10103dc
     field public static final int targetPackage = 16842785; // 0x1010021
     field public static final int targetSdkVersion = 16843376; // 0x1010270
-    field public static final int targetViewName = 16843857; // 0x1010451
+    field public static final int targetViewName = 16843856; // 0x1010450
     field public static final int taskAffinity = 16842770; // 0x1010012
     field public static final int taskCloseEnterAnimation = 16842942; // 0x10100be
     field public static final int taskCloseExitAnimation = 16842943; // 0x10100bf
@@ -1149,7 +1152,7 @@
     field public static final int textAppearanceLargeInverse = 16842819; // 0x1010043
     field public static final int textAppearanceLargePopupMenu = 16843521; // 0x1010301
     field public static final int textAppearanceListItem = 16843678; // 0x101039e
-    field public static final int textAppearanceListItemSecondary = 16843830; // 0x1010436
+    field public static final int textAppearanceListItemSecondary = 16843829; // 0x1010435
     field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
     field public static final int textAppearanceMedium = 16842817; // 0x1010041
     field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
@@ -1210,14 +1213,14 @@
     field public static final int tileMode = 16843265; // 0x1010201
     field public static final int timeZone = 16843724; // 0x10103cc
     field public static final int tint = 16843041; // 0x1010121
-    field public static final int tintMode = 16843798; // 0x1010416
+    field public static final int tintMode = 16843797; // 0x1010415
     field public static final int title = 16843233; // 0x10101e1
     field public static final int titleCondensed = 16843234; // 0x10101e2
-    field public static final int titleTextAppearance = 16843826; // 0x1010432
+    field public static final int titleTextAppearance = 16843825; // 0x1010431
     field public static final int titleTextStyle = 16843512; // 0x10102f8
     field public static final int toAlpha = 16843211; // 0x10101cb
     field public static final int toDegrees = 16843188; // 0x10101b4
-    field public static final int toId = 16843853; // 0x101044d
+    field public static final int toId = 16843852; // 0x101044c
     field public static final int toScene = 16843742; // 0x10103de
     field public static final int toXDelta = 16843207; // 0x10101c7
     field public static final int toXScale = 16843203; // 0x10101c3
@@ -1234,14 +1237,14 @@
     field public static final int transformPivotX = 16843552; // 0x1010320
     field public static final int transformPivotY = 16843553; // 0x1010321
     field public static final int transition = 16843743; // 0x10103df
-    field public static final int transitionGroup = 16843804; // 0x101041c
+    field public static final int transitionGroup = 16843803; // 0x101041b
     field public static final int transitionOrdering = 16843744; // 0x10103e0
     field public static final int translationX = 16843554; // 0x1010322
     field public static final int translationY = 16843555; // 0x1010323
-    field public static final int translationZ = 16843797; // 0x1010415
-    field public static final int trimPathEnd = 16843814; // 0x1010426
-    field public static final int trimPathOffset = 16843815; // 0x1010427
-    field public static final int trimPathStart = 16843813; // 0x1010425
+    field public static final int translationZ = 16843796; // 0x1010414
+    field public static final int trimPathEnd = 16843813; // 0x1010425
+    field public static final int trimPathOffset = 16843814; // 0x1010426
+    field public static final int trimPathStart = 16843812; // 0x1010424
     field public static final int type = 16843169; // 0x10101a1
     field public static final int typeface = 16842902; // 0x1010096
     field public static final int uiOptions = 16843672; // 0x1010398
@@ -1266,9 +1269,9 @@
     field public static final int verticalGap = 16843328; // 0x1010240
     field public static final int verticalScrollbarPosition = 16843572; // 0x1010334
     field public static final int verticalSpacing = 16843029; // 0x1010115
-    field public static final int viewName = 16843803; // 0x101041b
-    field public static final int viewportHeight = 16843806; // 0x101041e
-    field public static final int viewportWidth = 16843805; // 0x101041d
+    field public static final int viewName = 16843802; // 0x101041a
+    field public static final int viewportHeight = 16843805; // 0x101041d
+    field public static final int viewportWidth = 16843804; // 0x101041c
     field public static final int visibility = 16842972; // 0x10100dc
     field public static final int visible = 16843156; // 0x1010194
     field public static final int vmSafeMode = 16843448; // 0x10102b8
@@ -1297,20 +1300,21 @@
     field public static final int windowActionBar = 16843469; // 0x10102cd
     field public static final int windowActionBarOverlay = 16843492; // 0x10102e4
     field public static final int windowActionModeOverlay = 16843485; // 0x10102dd
-    field public static final int windowAllowEnterTransitionOverlap = 16843841; // 0x1010441
-    field public static final int windowAllowExitTransitionOverlap = 16843840; // 0x1010440
+    field public static final int windowAllowEnterTransitionOverlap = 16843840; // 0x1010440
+    field public static final int windowAllowExitTransitionOverlap = 16843839; // 0x101043f
     field public static final int windowAnimationStyle = 16842926; // 0x10100ae
     field public static final int windowBackground = 16842836; // 0x1010054
     field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
     field public static final int windowContentOverlay = 16842841; // 0x1010059
-    field public static final int windowContentTransitionManager = 16843796; // 0x1010414
-    field public static final int windowContentTransitions = 16843795; // 0x1010413
+    field public static final int windowContentTransitionManager = 16843795; // 0x1010413
+    field public static final int windowContentTransitions = 16843794; // 0x1010412
     field public static final int windowDisablePreview = 16843298; // 0x1010222
+    field public static final int windowDrawsSystemBarBackgrounds = 16843859; // 0x1010453
     field public static final int windowEnableSplitTouch = 16843543; // 0x1010317
     field public static final int windowEnterAnimation = 16842932; // 0x10100b4
-    field public static final int windowEnterTransition = 16843836; // 0x101043c
+    field public static final int windowEnterTransition = 16843835; // 0x101043b
     field public static final int windowExitAnimation = 16842933; // 0x10100b5
-    field public static final int windowExitTransition = 16843837; // 0x101043d
+    field public static final int windowExitTransition = 16843836; // 0x101043c
     field public static final int windowFrame = 16842837; // 0x1010055
     field public static final int windowFullscreen = 16843277; // 0x101020d
     field public static final int windowHideAnimation = 16842935; // 0x10100b7
@@ -1321,8 +1325,8 @@
     field public static final int windowNoDisplay = 16843294; // 0x101021e
     field public static final int windowNoTitle = 16842838; // 0x1010056
     field public static final int windowOverscan = 16843727; // 0x10103cf
-    field public static final int windowSharedElementEnterTransition = 16843838; // 0x101043e
-    field public static final int windowSharedElementExitTransition = 16843839; // 0x101043f
+    field public static final int windowSharedElementEnterTransition = 16843837; // 0x101043d
+    field public static final int windowSharedElementExitTransition = 16843838; // 0x101043e
     field public static final int windowShowAnimation = 16842934; // 0x10100b6
     field public static final int windowShowWallpaper = 16843410; // 0x1010292
     field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -1859,52 +1863,52 @@
     field public static final int TextAppearance_Large_Inverse = 16973891; // 0x1030043
     field public static final int TextAppearance_Medium = 16973892; // 0x1030044
     field public static final int TextAppearance_Medium_Inverse = 16973893; // 0x1030045
-    field public static final int TextAppearance_Quantum = 16974352; // 0x1030210
-    field public static final int TextAppearance_Quantum_Body1 = 16974549; // 0x10302d5
-    field public static final int TextAppearance_Quantum_Body2 = 16974548; // 0x10302d4
-    field public static final int TextAppearance_Quantum_Button = 16974552; // 0x10302d8
-    field public static final int TextAppearance_Quantum_Caption = 16974550; // 0x10302d6
-    field public static final int TextAppearance_Quantum_DialogWindowTitle = 16974353; // 0x1030211
-    field public static final int TextAppearance_Quantum_Display1 = 16974544; // 0x10302d0
-    field public static final int TextAppearance_Quantum_Display2 = 16974543; // 0x10302cf
-    field public static final int TextAppearance_Quantum_Display3 = 16974542; // 0x10302ce
-    field public static final int TextAppearance_Quantum_Display4 = 16974541; // 0x10302cd
-    field public static final int TextAppearance_Quantum_Headline = 16974545; // 0x10302d1
-    field public static final int TextAppearance_Quantum_Inverse = 16974354; // 0x1030212
-    field public static final int TextAppearance_Quantum_Large = 16974355; // 0x1030213
-    field public static final int TextAppearance_Quantum_Large_Inverse = 16974356; // 0x1030214
-    field public static final int TextAppearance_Quantum_Medium = 16974357; // 0x1030215
-    field public static final int TextAppearance_Quantum_Medium_Inverse = 16974358; // 0x1030216
-    field public static final int TextAppearance_Quantum_Menu = 16974551; // 0x10302d7
-    field public static final int TextAppearance_Quantum_SearchResult_Subtitle = 16974359; // 0x1030217
-    field public static final int TextAppearance_Quantum_SearchResult_Title = 16974360; // 0x1030218
-    field public static final int TextAppearance_Quantum_Small = 16974361; // 0x1030219
-    field public static final int TextAppearance_Quantum_Small_Inverse = 16974362; // 0x103021a
-    field public static final int TextAppearance_Quantum_Subhead = 16974547; // 0x10302d3
-    field public static final int TextAppearance_Quantum_Title = 16974546; // 0x10302d2
-    field public static final int TextAppearance_Quantum_Widget = 16974364; // 0x103021c
-    field public static final int TextAppearance_Quantum_Widget_ActionBar_Menu = 16974365; // 0x103021d
-    field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle = 16974366; // 0x103021e
-    field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle_Inverse = 16974367; // 0x103021f
-    field public static final int TextAppearance_Quantum_Widget_ActionBar_Title = 16974368; // 0x1030220
-    field public static final int TextAppearance_Quantum_Widget_ActionBar_Title_Inverse = 16974369; // 0x1030221
-    field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle = 16974370; // 0x1030222
-    field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle_Inverse = 16974371; // 0x1030223
-    field public static final int TextAppearance_Quantum_Widget_ActionMode_Title = 16974372; // 0x1030224
-    field public static final int TextAppearance_Quantum_Widget_ActionMode_Title_Inverse = 16974373; // 0x1030225
-    field public static final int TextAppearance_Quantum_Widget_Button = 16974374; // 0x1030226
-    field public static final int TextAppearance_Quantum_Widget_DropDownHint = 16974375; // 0x1030227
-    field public static final int TextAppearance_Quantum_Widget_DropDownItem = 16974376; // 0x1030228
-    field public static final int TextAppearance_Quantum_Widget_EditText = 16974377; // 0x1030229
-    field public static final int TextAppearance_Quantum_Widget_IconMenu_Item = 16974378; // 0x103022a
-    field public static final int TextAppearance_Quantum_Widget_PopupMenu = 16974379; // 0x103022b
-    field public static final int TextAppearance_Quantum_Widget_PopupMenu_Large = 16974380; // 0x103022c
-    field public static final int TextAppearance_Quantum_Widget_PopupMenu_Small = 16974381; // 0x103022d
-    field public static final int TextAppearance_Quantum_Widget_TabWidget = 16974382; // 0x103022e
-    field public static final int TextAppearance_Quantum_Widget_TextView = 16974383; // 0x103022f
-    field public static final int TextAppearance_Quantum_Widget_TextView_PopupMenu = 16974384; // 0x1030230
-    field public static final int TextAppearance_Quantum_Widget_TextView_SpinnerItem = 16974385; // 0x1030231
-    field public static final int TextAppearance_Quantum_WindowTitle = 16974363; // 0x103021b
+    field public static final int TextAppearance_Quantum = 16974348; // 0x103020c
+    field public static final int TextAppearance_Quantum_Body1 = 16974543; // 0x10302cf
+    field public static final int TextAppearance_Quantum_Body2 = 16974542; // 0x10302ce
+    field public static final int TextAppearance_Quantum_Button = 16974546; // 0x10302d2
+    field public static final int TextAppearance_Quantum_Caption = 16974544; // 0x10302d0
+    field public static final int TextAppearance_Quantum_DialogWindowTitle = 16974349; // 0x103020d
+    field public static final int TextAppearance_Quantum_Display1 = 16974538; // 0x10302ca
+    field public static final int TextAppearance_Quantum_Display2 = 16974537; // 0x10302c9
+    field public static final int TextAppearance_Quantum_Display3 = 16974536; // 0x10302c8
+    field public static final int TextAppearance_Quantum_Display4 = 16974535; // 0x10302c7
+    field public static final int TextAppearance_Quantum_Headline = 16974539; // 0x10302cb
+    field public static final int TextAppearance_Quantum_Inverse = 16974350; // 0x103020e
+    field public static final int TextAppearance_Quantum_Large = 16974351; // 0x103020f
+    field public static final int TextAppearance_Quantum_Large_Inverse = 16974352; // 0x1030210
+    field public static final int TextAppearance_Quantum_Medium = 16974353; // 0x1030211
+    field public static final int TextAppearance_Quantum_Medium_Inverse = 16974354; // 0x1030212
+    field public static final int TextAppearance_Quantum_Menu = 16974545; // 0x10302d1
+    field public static final int TextAppearance_Quantum_SearchResult_Subtitle = 16974355; // 0x1030213
+    field public static final int TextAppearance_Quantum_SearchResult_Title = 16974356; // 0x1030214
+    field public static final int TextAppearance_Quantum_Small = 16974357; // 0x1030215
+    field public static final int TextAppearance_Quantum_Small_Inverse = 16974358; // 0x1030216
+    field public static final int TextAppearance_Quantum_Subhead = 16974541; // 0x10302cd
+    field public static final int TextAppearance_Quantum_Title = 16974540; // 0x10302cc
+    field public static final int TextAppearance_Quantum_Widget = 16974360; // 0x1030218
+    field public static final int TextAppearance_Quantum_Widget_ActionBar_Menu = 16974361; // 0x1030219
+    field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle = 16974362; // 0x103021a
+    field public static final int TextAppearance_Quantum_Widget_ActionBar_Subtitle_Inverse = 16974363; // 0x103021b
+    field public static final int TextAppearance_Quantum_Widget_ActionBar_Title = 16974364; // 0x103021c
+    field public static final int TextAppearance_Quantum_Widget_ActionBar_Title_Inverse = 16974365; // 0x103021d
+    field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle = 16974366; // 0x103021e
+    field public static final int TextAppearance_Quantum_Widget_ActionMode_Subtitle_Inverse = 16974367; // 0x103021f
+    field public static final int TextAppearance_Quantum_Widget_ActionMode_Title = 16974368; // 0x1030220
+    field public static final int TextAppearance_Quantum_Widget_ActionMode_Title_Inverse = 16974369; // 0x1030221
+    field public static final int TextAppearance_Quantum_Widget_Button = 16974370; // 0x1030222
+    field public static final int TextAppearance_Quantum_Widget_DropDownHint = 16974371; // 0x1030223
+    field public static final int TextAppearance_Quantum_Widget_DropDownItem = 16974372; // 0x1030224
+    field public static final int TextAppearance_Quantum_Widget_EditText = 16974373; // 0x1030225
+    field public static final int TextAppearance_Quantum_Widget_IconMenu_Item = 16974374; // 0x1030226
+    field public static final int TextAppearance_Quantum_Widget_PopupMenu = 16974375; // 0x1030227
+    field public static final int TextAppearance_Quantum_Widget_PopupMenu_Large = 16974376; // 0x1030228
+    field public static final int TextAppearance_Quantum_Widget_PopupMenu_Small = 16974377; // 0x1030229
+    field public static final int TextAppearance_Quantum_Widget_TabWidget = 16974378; // 0x103022a
+    field public static final int TextAppearance_Quantum_Widget_TextView = 16974379; // 0x103022b
+    field public static final int TextAppearance_Quantum_Widget_TextView_PopupMenu = 16974380; // 0x103022c
+    field public static final int TextAppearance_Quantum_Widget_TextView_SpinnerItem = 16974381; // 0x103022d
+    field public static final int TextAppearance_Quantum_WindowTitle = 16974359; // 0x1030217
     field public static final int TextAppearance_Small = 16973894; // 0x1030046
     field public static final int TextAppearance_Small_Inverse = 16973895; // 0x1030047
     field public static final int TextAppearance_StatusBar_EventContent = 16973927; // 0x1030067
@@ -1928,11 +1932,11 @@
     field public static final int TextAppearance_Widget_TextView_SpinnerItem = 16973906; // 0x1030052
     field public static final int TextAppearance_WindowTitle = 16973907; // 0x1030053
     field public static final int Theme = 16973829; // 0x1030005
-    field public static final int ThemeOverlay = 16974414; // 0x103024e
-    field public static final int ThemeOverlay_Quantum = 16974415; // 0x103024f
-    field public static final int ThemeOverlay_Quantum_ActionBarWidget = 16974418; // 0x1030252
-    field public static final int ThemeOverlay_Quantum_Dark = 16974417; // 0x1030251
-    field public static final int ThemeOverlay_Quantum_Light = 16974416; // 0x1030250
+    field public static final int ThemeOverlay = 16974410; // 0x103024a
+    field public static final int ThemeOverlay_Quantum = 16974411; // 0x103024b
+    field public static final int ThemeOverlay_Quantum_ActionBarWidget = 16974414; // 0x103024e
+    field public static final int ThemeOverlay_Quantum_Dark = 16974413; // 0x103024d
+    field public static final int ThemeOverlay_Quantum_Light = 16974412; // 0x103024c
     field public static final int Theme_Black = 16973832; // 0x1030008
     field public static final int Theme_Black_NoTitleBar = 16973833; // 0x1030009
     field public static final int Theme_Black_NoTitleBar_Fullscreen = 16973834; // 0x103000a
@@ -2004,34 +2008,34 @@
     field public static final int Theme_NoTitleBar_Fullscreen = 16973831; // 0x1030007
     field public static final int Theme_NoTitleBar_OverlayActionModes = 16973930; // 0x103006a
     field public static final int Theme_Panel = 16973913; // 0x1030059
-    field public static final int Theme_Quantum = 16974386; // 0x1030232
-    field public static final int Theme_Quantum_Dialog = 16974387; // 0x1030233
-    field public static final int Theme_Quantum_DialogWhenLarge = 16974391; // 0x1030237
-    field public static final int Theme_Quantum_DialogWhenLarge_NoActionBar = 16974392; // 0x1030238
-    field public static final int Theme_Quantum_Dialog_MinWidth = 16974388; // 0x1030234
-    field public static final int Theme_Quantum_Dialog_NoActionBar = 16974389; // 0x1030235
-    field public static final int Theme_Quantum_Dialog_NoActionBar_MinWidth = 16974390; // 0x1030236
-    field public static final int Theme_Quantum_InputMethod = 16974393; // 0x1030239
-    field public static final int Theme_Quantum_Light = 16974401; // 0x1030241
-    field public static final int Theme_Quantum_Light_DarkActionBar = 16974402; // 0x1030242
-    field public static final int Theme_Quantum_Light_Dialog = 16974403; // 0x1030243
-    field public static final int Theme_Quantum_Light_DialogWhenLarge = 16974407; // 0x1030247
-    field public static final int Theme_Quantum_Light_DialogWhenLarge_NoActionBar = 16974408; // 0x1030248
-    field public static final int Theme_Quantum_Light_Dialog_MinWidth = 16974404; // 0x1030244
-    field public static final int Theme_Quantum_Light_Dialog_NoActionBar = 16974405; // 0x1030245
-    field public static final int Theme_Quantum_Light_Dialog_NoActionBar_MinWidth = 16974406; // 0x1030246
-    field public static final int Theme_Quantum_Light_NoActionBar = 16974409; // 0x1030249
-    field public static final int Theme_Quantum_Light_NoActionBar_Fullscreen = 16974410; // 0x103024a
-    field public static final int Theme_Quantum_Light_NoActionBar_Overscan = 16974411; // 0x103024b
-    field public static final int Theme_Quantum_Light_NoActionBar_TranslucentDecor = 16974412; // 0x103024c
-    field public static final int Theme_Quantum_Light_Panel = 16974413; // 0x103024d
-    field public static final int Theme_Quantum_NoActionBar = 16974394; // 0x103023a
-    field public static final int Theme_Quantum_NoActionBar_Fullscreen = 16974395; // 0x103023b
-    field public static final int Theme_Quantum_NoActionBar_Overscan = 16974396; // 0x103023c
-    field public static final int Theme_Quantum_NoActionBar_TranslucentDecor = 16974397; // 0x103023d
-    field public static final int Theme_Quantum_Panel = 16974398; // 0x103023e
-    field public static final int Theme_Quantum_Wallpaper = 16974399; // 0x103023f
-    field public static final int Theme_Quantum_Wallpaper_NoTitleBar = 16974400; // 0x1030240
+    field public static final int Theme_Quantum = 16974382; // 0x103022e
+    field public static final int Theme_Quantum_Dialog = 16974383; // 0x103022f
+    field public static final int Theme_Quantum_DialogWhenLarge = 16974387; // 0x1030233
+    field public static final int Theme_Quantum_DialogWhenLarge_NoActionBar = 16974388; // 0x1030234
+    field public static final int Theme_Quantum_Dialog_MinWidth = 16974384; // 0x1030230
+    field public static final int Theme_Quantum_Dialog_NoActionBar = 16974385; // 0x1030231
+    field public static final int Theme_Quantum_Dialog_NoActionBar_MinWidth = 16974386; // 0x1030232
+    field public static final int Theme_Quantum_InputMethod = 16974389; // 0x1030235
+    field public static final int Theme_Quantum_Light = 16974397; // 0x103023d
+    field public static final int Theme_Quantum_Light_DarkActionBar = 16974398; // 0x103023e
+    field public static final int Theme_Quantum_Light_Dialog = 16974399; // 0x103023f
+    field public static final int Theme_Quantum_Light_DialogWhenLarge = 16974403; // 0x1030243
+    field public static final int Theme_Quantum_Light_DialogWhenLarge_NoActionBar = 16974404; // 0x1030244
+    field public static final int Theme_Quantum_Light_Dialog_MinWidth = 16974400; // 0x1030240
+    field public static final int Theme_Quantum_Light_Dialog_NoActionBar = 16974401; // 0x1030241
+    field public static final int Theme_Quantum_Light_Dialog_NoActionBar_MinWidth = 16974402; // 0x1030242
+    field public static final int Theme_Quantum_Light_NoActionBar = 16974405; // 0x1030245
+    field public static final int Theme_Quantum_Light_NoActionBar_Fullscreen = 16974406; // 0x1030246
+    field public static final int Theme_Quantum_Light_NoActionBar_Overscan = 16974407; // 0x1030247
+    field public static final int Theme_Quantum_Light_NoActionBar_TranslucentDecor = 16974408; // 0x1030248
+    field public static final int Theme_Quantum_Light_Panel = 16974409; // 0x1030249
+    field public static final int Theme_Quantum_NoActionBar = 16974390; // 0x1030236
+    field public static final int Theme_Quantum_NoActionBar_Fullscreen = 16974391; // 0x1030237
+    field public static final int Theme_Quantum_NoActionBar_Overscan = 16974392; // 0x1030238
+    field public static final int Theme_Quantum_NoActionBar_TranslucentDecor = 16974393; // 0x1030239
+    field public static final int Theme_Quantum_Panel = 16974394; // 0x103023a
+    field public static final int Theme_Quantum_Wallpaper = 16974395; // 0x103023b
+    field public static final int Theme_Quantum_Wallpaper_NoTitleBar = 16974396; // 0x103023c
     field public static final int Theme_Translucent = 16973839; // 0x103000f
     field public static final int Theme_Translucent_NoTitleBar = 16973840; // 0x1030010
     field public static final int Theme_Translucent_NoTitleBar_Fullscreen = 16973841; // 0x1030011
@@ -2088,8 +2092,7 @@
     field public static final int Widget_DeviceDefault_DropDownItem_Spinner = 16974178; // 0x1030162
     field public static final int Widget_DeviceDefault_EditText = 16974154; // 0x103014a
     field public static final int Widget_DeviceDefault_ExpandableListView = 16974155; // 0x103014b
-    field public static final int Widget_DeviceDefault_FastScroll = 16974346; // 0x103020a
-    field public static final int Widget_DeviceDefault_FragmentBreadCrumbs = 16974347; // 0x103020b
+    field public static final int Widget_DeviceDefault_FastScroll = 16974344; // 0x1030208
     field public static final int Widget_DeviceDefault_GridView = 16974156; // 0x103014c
     field public static final int Widget_DeviceDefault_HorizontalScrollView = 16974171; // 0x103015b
     field public static final int Widget_DeviceDefault_ImageButton = 16974157; // 0x103014d
@@ -2123,8 +2126,7 @@
     field public static final int Widget_DeviceDefault_Light_DropDownItem_Spinner = 16974233; // 0x1030199
     field public static final int Widget_DeviceDefault_Light_EditText = 16974206; // 0x103017e
     field public static final int Widget_DeviceDefault_Light_ExpandableListView = 16974207; // 0x103017f
-    field public static final int Widget_DeviceDefault_Light_FastScroll = 16974349; // 0x103020d
-    field public static final int Widget_DeviceDefault_Light_FragmentBreadCrumbs = 16974350; // 0x103020e
+    field public static final int Widget_DeviceDefault_Light_FastScroll = 16974346; // 0x103020a
     field public static final int Widget_DeviceDefault_Light_GridView = 16974208; // 0x1030180
     field public static final int Widget_DeviceDefault_Light_HorizontalScrollView = 16974226; // 0x1030192
     field public static final int Widget_DeviceDefault_Light_ImageButton = 16974209; // 0x1030181
@@ -2148,7 +2150,7 @@
     field public static final int Widget_DeviceDefault_Light_ScrollView = 16974225; // 0x1030191
     field public static final int Widget_DeviceDefault_Light_SeekBar = 16974220; // 0x103018c
     field public static final int Widget_DeviceDefault_Light_Spinner = 16974227; // 0x1030193
-    field public static final int Widget_DeviceDefault_Light_StackView = 16974351; // 0x103020f
+    field public static final int Widget_DeviceDefault_Light_StackView = 16974347; // 0x103020b
     field public static final int Widget_DeviceDefault_Light_Tab = 16974237; // 0x103019d
     field public static final int Widget_DeviceDefault_Light_TabWidget = 16974229; // 0x1030195
     field public static final int Widget_DeviceDefault_Light_TextView = 16974202; // 0x103017a
@@ -2172,7 +2174,7 @@
     field public static final int Widget_DeviceDefault_ScrollView = 16974170; // 0x103015a
     field public static final int Widget_DeviceDefault_SeekBar = 16974165; // 0x1030155
     field public static final int Widget_DeviceDefault_Spinner = 16974172; // 0x103015c
-    field public static final int Widget_DeviceDefault_StackView = 16974348; // 0x103020c
+    field public static final int Widget_DeviceDefault_StackView = 16974345; // 0x1030209
     field public static final int Widget_DeviceDefault_Tab = 16974189; // 0x103016d
     field public static final int Widget_DeviceDefault_TabWidget = 16974174; // 0x103015e
     field public static final int Widget_DeviceDefault_TextView = 16974150; // 0x1030146
@@ -2216,7 +2218,6 @@
     field public static final int Widget_Holo_EditText = 16973971; // 0x1030093
     field public static final int Widget_Holo_ExpandableListView = 16973972; // 0x1030094
     field public static final int Widget_Holo_FastScroll = 16974339; // 0x1030203
-    field public static final int Widget_Holo_FragmentBreadCrumbs = 16974340; // 0x1030204
     field public static final int Widget_Holo_GridView = 16973973; // 0x1030095
     field public static final int Widget_Holo_HorizontalScrollView = 16973988; // 0x10300a4
     field public static final int Widget_Holo_ImageButton = 16973974; // 0x1030096
@@ -2237,7 +2238,7 @@
     field public static final int Widget_Holo_Light_ActionMode_Inverse = 16974119; // 0x1030127
     field public static final int Widget_Holo_Light_AutoCompleteTextView = 16974011; // 0x10300bb
     field public static final int Widget_Holo_Light_Button = 16974006; // 0x10300b6
-    field public static final int Widget_Holo_Light_Button_Borderless = 16974342; // 0x1030206
+    field public static final int Widget_Holo_Light_Button_Borderless = 16974341; // 0x1030205
     field public static final int Widget_Holo_Light_Button_Borderless_Small = 16974107; // 0x103011b
     field public static final int Widget_Holo_Light_Button_Inset = 16974008; // 0x10300b8
     field public static final int Widget_Holo_Light_Button_Small = 16974007; // 0x10300b7
@@ -2251,8 +2252,7 @@
     field public static final int Widget_Holo_Light_DropDownItem_Spinner = 16974041; // 0x10300d9
     field public static final int Widget_Holo_Light_EditText = 16974014; // 0x10300be
     field public static final int Widget_Holo_Light_ExpandableListView = 16974015; // 0x10300bf
-    field public static final int Widget_Holo_Light_FastScroll = 16974343; // 0x1030207
-    field public static final int Widget_Holo_Light_FragmentBreadCrumbs = 16974344; // 0x1030208
+    field public static final int Widget_Holo_Light_FastScroll = 16974342; // 0x1030206
     field public static final int Widget_Holo_Light_GridView = 16974016; // 0x10300c0
     field public static final int Widget_Holo_Light_HorizontalScrollView = 16974034; // 0x10300d2
     field public static final int Widget_Holo_Light_ImageButton = 16974017; // 0x10300c1
@@ -2276,7 +2276,7 @@
     field public static final int Widget_Holo_Light_ScrollView = 16974033; // 0x10300d1
     field public static final int Widget_Holo_Light_SeekBar = 16974028; // 0x10300cc
     field public static final int Widget_Holo_Light_Spinner = 16974035; // 0x10300d3
-    field public static final int Widget_Holo_Light_StackView = 16974345; // 0x1030209
+    field public static final int Widget_Holo_Light_StackView = 16974343; // 0x1030207
     field public static final int Widget_Holo_Light_Tab = 16974052; // 0x10300e4
     field public static final int Widget_Holo_Light_TabWidget = 16974037; // 0x10300d5
     field public static final int Widget_Holo_Light_TextView = 16974010; // 0x10300ba
@@ -2300,7 +2300,7 @@
     field public static final int Widget_Holo_ScrollView = 16973987; // 0x10300a3
     field public static final int Widget_Holo_SeekBar = 16973982; // 0x103009e
     field public static final int Widget_Holo_Spinner = 16973989; // 0x10300a5
-    field public static final int Widget_Holo_StackView = 16974341; // 0x1030205
+    field public static final int Widget_Holo_StackView = 16974340; // 0x1030204
     field public static final int Widget_Holo_Tab = 16974051; // 0x10300e3
     field public static final int Widget_Holo_TabWidget = 16973991; // 0x10300a7
     field public static final int Widget_Holo_TextView = 16973967; // 0x103008f
@@ -2324,128 +2324,126 @@
     field public static final int Widget_ProgressBar_Large_Inverse = 16973916; // 0x103005c
     field public static final int Widget_ProgressBar_Small = 16973854; // 0x103001e
     field public static final int Widget_ProgressBar_Small_Inverse = 16973917; // 0x103005d
-    field public static final int Widget_Quantum = 16974419; // 0x1030253
-    field public static final int Widget_Quantum_ActionBar = 16974420; // 0x1030254
-    field public static final int Widget_Quantum_ActionBar_Solid = 16974421; // 0x1030255
-    field public static final int Widget_Quantum_ActionBar_TabBar = 16974422; // 0x1030256
-    field public static final int Widget_Quantum_ActionBar_TabText = 16974423; // 0x1030257
-    field public static final int Widget_Quantum_ActionBar_TabView = 16974424; // 0x1030258
-    field public static final int Widget_Quantum_ActionButton = 16974425; // 0x1030259
-    field public static final int Widget_Quantum_ActionButton_CloseMode = 16974426; // 0x103025a
-    field public static final int Widget_Quantum_ActionButton_Overflow = 16974427; // 0x103025b
-    field public static final int Widget_Quantum_ActionMode = 16974428; // 0x103025c
-    field public static final int Widget_Quantum_AutoCompleteTextView = 16974429; // 0x103025d
-    field public static final int Widget_Quantum_Button = 16974430; // 0x103025e
-    field public static final int Widget_Quantum_ButtonBar = 16974436; // 0x1030264
-    field public static final int Widget_Quantum_ButtonBar_AlertDialog = 16974437; // 0x1030265
-    field public static final int Widget_Quantum_Button_Borderless = 16974431; // 0x103025f
-    field public static final int Widget_Quantum_Button_Borderless_Small = 16974432; // 0x1030260
-    field public static final int Widget_Quantum_Button_Inset = 16974433; // 0x1030261
-    field public static final int Widget_Quantum_Button_Small = 16974434; // 0x1030262
-    field public static final int Widget_Quantum_Button_Toggle = 16974435; // 0x1030263
-    field public static final int Widget_Quantum_CalendarView = 16974438; // 0x1030266
-    field public static final int Widget_Quantum_CheckedTextView = 16974439; // 0x1030267
-    field public static final int Widget_Quantum_CompoundButton_CheckBox = 16974440; // 0x1030268
-    field public static final int Widget_Quantum_CompoundButton_RadioButton = 16974441; // 0x1030269
-    field public static final int Widget_Quantum_CompoundButton_Star = 16974442; // 0x103026a
-    field public static final int Widget_Quantum_DatePicker = 16974443; // 0x103026b
-    field public static final int Widget_Quantum_DropDownItem = 16974444; // 0x103026c
-    field public static final int Widget_Quantum_DropDownItem_Spinner = 16974445; // 0x103026d
-    field public static final int Widget_Quantum_EditText = 16974446; // 0x103026e
-    field public static final int Widget_Quantum_ExpandableListView = 16974447; // 0x103026f
-    field public static final int Widget_Quantum_FastScroll = 16974448; // 0x1030270
-    field public static final int Widget_Quantum_FragmentBreadCrumbs = 16974449; // 0x1030271
-    field public static final int Widget_Quantum_GridView = 16974450; // 0x1030272
-    field public static final int Widget_Quantum_HorizontalScrollView = 16974451; // 0x1030273
-    field public static final int Widget_Quantum_ImageButton = 16974452; // 0x1030274
-    field public static final int Widget_Quantum_Light = 16974479; // 0x103028f
-    field public static final int Widget_Quantum_Light_ActionBar = 16974480; // 0x1030290
-    field public static final int Widget_Quantum_Light_ActionBar_Solid = 16974481; // 0x1030291
-    field public static final int Widget_Quantum_Light_ActionBar_TabBar = 16974482; // 0x1030292
-    field public static final int Widget_Quantum_Light_ActionBar_TabText = 16974483; // 0x1030293
-    field public static final int Widget_Quantum_Light_ActionBar_TabView = 16974484; // 0x1030294
-    field public static final int Widget_Quantum_Light_ActionButton = 16974485; // 0x1030295
-    field public static final int Widget_Quantum_Light_ActionButton_CloseMode = 16974486; // 0x1030296
-    field public static final int Widget_Quantum_Light_ActionButton_Overflow = 16974487; // 0x1030297
-    field public static final int Widget_Quantum_Light_ActionMode = 16974488; // 0x1030298
-    field public static final int Widget_Quantum_Light_AutoCompleteTextView = 16974489; // 0x1030299
-    field public static final int Widget_Quantum_Light_Button = 16974490; // 0x103029a
-    field public static final int Widget_Quantum_Light_ButtonBar = 16974496; // 0x10302a0
-    field public static final int Widget_Quantum_Light_ButtonBar_AlertDialog = 16974497; // 0x10302a1
-    field public static final int Widget_Quantum_Light_Button_Borderless = 16974491; // 0x103029b
-    field public static final int Widget_Quantum_Light_Button_Borderless_Small = 16974492; // 0x103029c
-    field public static final int Widget_Quantum_Light_Button_Inset = 16974493; // 0x103029d
-    field public static final int Widget_Quantum_Light_Button_Small = 16974494; // 0x103029e
-    field public static final int Widget_Quantum_Light_Button_Toggle = 16974495; // 0x103029f
-    field public static final int Widget_Quantum_Light_CalendarView = 16974498; // 0x10302a2
-    field public static final int Widget_Quantum_Light_CheckedTextView = 16974499; // 0x10302a3
-    field public static final int Widget_Quantum_Light_CompoundButton_CheckBox = 16974500; // 0x10302a4
-    field public static final int Widget_Quantum_Light_CompoundButton_RadioButton = 16974501; // 0x10302a5
-    field public static final int Widget_Quantum_Light_CompoundButton_Star = 16974502; // 0x10302a6
-    field public static final int Widget_Quantum_Light_DropDownItem = 16974503; // 0x10302a7
-    field public static final int Widget_Quantum_Light_DropDownItem_Spinner = 16974504; // 0x10302a8
-    field public static final int Widget_Quantum_Light_EditText = 16974505; // 0x10302a9
-    field public static final int Widget_Quantum_Light_ExpandableListView = 16974506; // 0x10302aa
-    field public static final int Widget_Quantum_Light_FastScroll = 16974507; // 0x10302ab
-    field public static final int Widget_Quantum_Light_FragmentBreadCrumbs = 16974508; // 0x10302ac
-    field public static final int Widget_Quantum_Light_GridView = 16974509; // 0x10302ad
-    field public static final int Widget_Quantum_Light_HorizontalScrollView = 16974510; // 0x10302ae
-    field public static final int Widget_Quantum_Light_ImageButton = 16974511; // 0x10302af
-    field public static final int Widget_Quantum_Light_ListPopupWindow = 16974512; // 0x10302b0
-    field public static final int Widget_Quantum_Light_ListView = 16974513; // 0x10302b1
-    field public static final int Widget_Quantum_Light_ListView_DropDown = 16974514; // 0x10302b2
-    field public static final int Widget_Quantum_Light_MediaRouteButton = 16974515; // 0x10302b3
-    field public static final int Widget_Quantum_Light_PopupMenu = 16974516; // 0x10302b4
-    field public static final int Widget_Quantum_Light_PopupMenu_Overflow = 16974517; // 0x10302b5
-    field public static final int Widget_Quantum_Light_PopupWindow = 16974518; // 0x10302b6
-    field public static final int Widget_Quantum_Light_ProgressBar = 16974519; // 0x10302b7
-    field public static final int Widget_Quantum_Light_ProgressBar_Horizontal = 16974520; // 0x10302b8
-    field public static final int Widget_Quantum_Light_ProgressBar_Inverse = 16974521; // 0x10302b9
-    field public static final int Widget_Quantum_Light_ProgressBar_Large = 16974522; // 0x10302ba
-    field public static final int Widget_Quantum_Light_ProgressBar_Large_Inverse = 16974523; // 0x10302bb
-    field public static final int Widget_Quantum_Light_ProgressBar_Small = 16974524; // 0x10302bc
-    field public static final int Widget_Quantum_Light_ProgressBar_Small_Inverse = 16974525; // 0x10302bd
-    field public static final int Widget_Quantum_Light_ProgressBar_Small_Title = 16974526; // 0x10302be
-    field public static final int Widget_Quantum_Light_RatingBar = 16974527; // 0x10302bf
-    field public static final int Widget_Quantum_Light_RatingBar_Indicator = 16974528; // 0x10302c0
-    field public static final int Widget_Quantum_Light_RatingBar_Small = 16974529; // 0x10302c1
-    field public static final int Widget_Quantum_Light_ScrollView = 16974530; // 0x10302c2
-    field public static final int Widget_Quantum_Light_SeekBar = 16974531; // 0x10302c3
-    field public static final int Widget_Quantum_Light_SegmentedButton = 16974532; // 0x10302c4
-    field public static final int Widget_Quantum_Light_Spinner = 16974534; // 0x10302c6
-    field public static final int Widget_Quantum_Light_StackView = 16974533; // 0x10302c5
-    field public static final int Widget_Quantum_Light_Tab = 16974535; // 0x10302c7
-    field public static final int Widget_Quantum_Light_TabWidget = 16974536; // 0x10302c8
-    field public static final int Widget_Quantum_Light_TextView = 16974537; // 0x10302c9
-    field public static final int Widget_Quantum_Light_TextView_SpinnerItem = 16974538; // 0x10302ca
-    field public static final int Widget_Quantum_Light_WebTextView = 16974539; // 0x10302cb
-    field public static final int Widget_Quantum_Light_WebView = 16974540; // 0x10302cc
-    field public static final int Widget_Quantum_ListPopupWindow = 16974453; // 0x1030275
-    field public static final int Widget_Quantum_ListView = 16974454; // 0x1030276
-    field public static final int Widget_Quantum_ListView_DropDown = 16974455; // 0x1030277
-    field public static final int Widget_Quantum_MediaRouteButton = 16974456; // 0x1030278
-    field public static final int Widget_Quantum_PopupMenu = 16974457; // 0x1030279
-    field public static final int Widget_Quantum_PopupMenu_Overflow = 16974458; // 0x103027a
-    field public static final int Widget_Quantum_PopupWindow = 16974459; // 0x103027b
-    field public static final int Widget_Quantum_ProgressBar = 16974460; // 0x103027c
-    field public static final int Widget_Quantum_ProgressBar_Horizontal = 16974461; // 0x103027d
-    field public static final int Widget_Quantum_ProgressBar_Large = 16974462; // 0x103027e
-    field public static final int Widget_Quantum_ProgressBar_Small = 16974463; // 0x103027f
-    field public static final int Widget_Quantum_ProgressBar_Small_Title = 16974464; // 0x1030280
-    field public static final int Widget_Quantum_RatingBar = 16974465; // 0x1030281
-    field public static final int Widget_Quantum_RatingBar_Indicator = 16974466; // 0x1030282
-    field public static final int Widget_Quantum_RatingBar_Small = 16974467; // 0x1030283
-    field public static final int Widget_Quantum_ScrollView = 16974468; // 0x1030284
-    field public static final int Widget_Quantum_SeekBar = 16974469; // 0x1030285
-    field public static final int Widget_Quantum_SegmentedButton = 16974470; // 0x1030286
-    field public static final int Widget_Quantum_Spinner = 16974472; // 0x1030288
-    field public static final int Widget_Quantum_StackView = 16974471; // 0x1030287
-    field public static final int Widget_Quantum_Tab = 16974473; // 0x1030289
-    field public static final int Widget_Quantum_TabWidget = 16974474; // 0x103028a
-    field public static final int Widget_Quantum_TextView = 16974475; // 0x103028b
-    field public static final int Widget_Quantum_TextView_SpinnerItem = 16974476; // 0x103028c
-    field public static final int Widget_Quantum_WebTextView = 16974477; // 0x103028d
-    field public static final int Widget_Quantum_WebView = 16974478; // 0x103028e
+    field public static final int Widget_Quantum = 16974415; // 0x103024f
+    field public static final int Widget_Quantum_ActionBar = 16974416; // 0x1030250
+    field public static final int Widget_Quantum_ActionBar_Solid = 16974417; // 0x1030251
+    field public static final int Widget_Quantum_ActionBar_TabBar = 16974418; // 0x1030252
+    field public static final int Widget_Quantum_ActionBar_TabText = 16974419; // 0x1030253
+    field public static final int Widget_Quantum_ActionBar_TabView = 16974420; // 0x1030254
+    field public static final int Widget_Quantum_ActionButton = 16974421; // 0x1030255
+    field public static final int Widget_Quantum_ActionButton_CloseMode = 16974422; // 0x1030256
+    field public static final int Widget_Quantum_ActionButton_Overflow = 16974423; // 0x1030257
+    field public static final int Widget_Quantum_ActionMode = 16974424; // 0x1030258
+    field public static final int Widget_Quantum_AutoCompleteTextView = 16974425; // 0x1030259
+    field public static final int Widget_Quantum_Button = 16974426; // 0x103025a
+    field public static final int Widget_Quantum_ButtonBar = 16974432; // 0x1030260
+    field public static final int Widget_Quantum_ButtonBar_AlertDialog = 16974433; // 0x1030261
+    field public static final int Widget_Quantum_Button_Borderless = 16974427; // 0x103025b
+    field public static final int Widget_Quantum_Button_Borderless_Small = 16974428; // 0x103025c
+    field public static final int Widget_Quantum_Button_Inset = 16974429; // 0x103025d
+    field public static final int Widget_Quantum_Button_Small = 16974430; // 0x103025e
+    field public static final int Widget_Quantum_Button_Toggle = 16974431; // 0x103025f
+    field public static final int Widget_Quantum_CalendarView = 16974434; // 0x1030262
+    field public static final int Widget_Quantum_CheckedTextView = 16974435; // 0x1030263
+    field public static final int Widget_Quantum_CompoundButton_CheckBox = 16974436; // 0x1030264
+    field public static final int Widget_Quantum_CompoundButton_RadioButton = 16974437; // 0x1030265
+    field public static final int Widget_Quantum_CompoundButton_Star = 16974438; // 0x1030266
+    field public static final int Widget_Quantum_DatePicker = 16974439; // 0x1030267
+    field public static final int Widget_Quantum_DropDownItem = 16974440; // 0x1030268
+    field public static final int Widget_Quantum_DropDownItem_Spinner = 16974441; // 0x1030269
+    field public static final int Widget_Quantum_EditText = 16974442; // 0x103026a
+    field public static final int Widget_Quantum_ExpandableListView = 16974443; // 0x103026b
+    field public static final int Widget_Quantum_FastScroll = 16974444; // 0x103026c
+    field public static final int Widget_Quantum_GridView = 16974445; // 0x103026d
+    field public static final int Widget_Quantum_HorizontalScrollView = 16974446; // 0x103026e
+    field public static final int Widget_Quantum_ImageButton = 16974447; // 0x103026f
+    field public static final int Widget_Quantum_Light = 16974474; // 0x103028a
+    field public static final int Widget_Quantum_Light_ActionBar = 16974475; // 0x103028b
+    field public static final int Widget_Quantum_Light_ActionBar_Solid = 16974476; // 0x103028c
+    field public static final int Widget_Quantum_Light_ActionBar_TabBar = 16974477; // 0x103028d
+    field public static final int Widget_Quantum_Light_ActionBar_TabText = 16974478; // 0x103028e
+    field public static final int Widget_Quantum_Light_ActionBar_TabView = 16974479; // 0x103028f
+    field public static final int Widget_Quantum_Light_ActionButton = 16974480; // 0x1030290
+    field public static final int Widget_Quantum_Light_ActionButton_CloseMode = 16974481; // 0x1030291
+    field public static final int Widget_Quantum_Light_ActionButton_Overflow = 16974482; // 0x1030292
+    field public static final int Widget_Quantum_Light_ActionMode = 16974483; // 0x1030293
+    field public static final int Widget_Quantum_Light_AutoCompleteTextView = 16974484; // 0x1030294
+    field public static final int Widget_Quantum_Light_Button = 16974485; // 0x1030295
+    field public static final int Widget_Quantum_Light_ButtonBar = 16974491; // 0x103029b
+    field public static final int Widget_Quantum_Light_ButtonBar_AlertDialog = 16974492; // 0x103029c
+    field public static final int Widget_Quantum_Light_Button_Borderless = 16974486; // 0x1030296
+    field public static final int Widget_Quantum_Light_Button_Borderless_Small = 16974487; // 0x1030297
+    field public static final int Widget_Quantum_Light_Button_Inset = 16974488; // 0x1030298
+    field public static final int Widget_Quantum_Light_Button_Small = 16974489; // 0x1030299
+    field public static final int Widget_Quantum_Light_Button_Toggle = 16974490; // 0x103029a
+    field public static final int Widget_Quantum_Light_CalendarView = 16974493; // 0x103029d
+    field public static final int Widget_Quantum_Light_CheckedTextView = 16974494; // 0x103029e
+    field public static final int Widget_Quantum_Light_CompoundButton_CheckBox = 16974495; // 0x103029f
+    field public static final int Widget_Quantum_Light_CompoundButton_RadioButton = 16974496; // 0x10302a0
+    field public static final int Widget_Quantum_Light_CompoundButton_Star = 16974497; // 0x10302a1
+    field public static final int Widget_Quantum_Light_DropDownItem = 16974498; // 0x10302a2
+    field public static final int Widget_Quantum_Light_DropDownItem_Spinner = 16974499; // 0x10302a3
+    field public static final int Widget_Quantum_Light_EditText = 16974500; // 0x10302a4
+    field public static final int Widget_Quantum_Light_ExpandableListView = 16974501; // 0x10302a5
+    field public static final int Widget_Quantum_Light_FastScroll = 16974502; // 0x10302a6
+    field public static final int Widget_Quantum_Light_GridView = 16974503; // 0x10302a7
+    field public static final int Widget_Quantum_Light_HorizontalScrollView = 16974504; // 0x10302a8
+    field public static final int Widget_Quantum_Light_ImageButton = 16974505; // 0x10302a9
+    field public static final int Widget_Quantum_Light_ListPopupWindow = 16974506; // 0x10302aa
+    field public static final int Widget_Quantum_Light_ListView = 16974507; // 0x10302ab
+    field public static final int Widget_Quantum_Light_ListView_DropDown = 16974508; // 0x10302ac
+    field public static final int Widget_Quantum_Light_MediaRouteButton = 16974509; // 0x10302ad
+    field public static final int Widget_Quantum_Light_PopupMenu = 16974510; // 0x10302ae
+    field public static final int Widget_Quantum_Light_PopupMenu_Overflow = 16974511; // 0x10302af
+    field public static final int Widget_Quantum_Light_PopupWindow = 16974512; // 0x10302b0
+    field public static final int Widget_Quantum_Light_ProgressBar = 16974513; // 0x10302b1
+    field public static final int Widget_Quantum_Light_ProgressBar_Horizontal = 16974514; // 0x10302b2
+    field public static final int Widget_Quantum_Light_ProgressBar_Inverse = 16974515; // 0x10302b3
+    field public static final int Widget_Quantum_Light_ProgressBar_Large = 16974516; // 0x10302b4
+    field public static final int Widget_Quantum_Light_ProgressBar_Large_Inverse = 16974517; // 0x10302b5
+    field public static final int Widget_Quantum_Light_ProgressBar_Small = 16974518; // 0x10302b6
+    field public static final int Widget_Quantum_Light_ProgressBar_Small_Inverse = 16974519; // 0x10302b7
+    field public static final int Widget_Quantum_Light_ProgressBar_Small_Title = 16974520; // 0x10302b8
+    field public static final int Widget_Quantum_Light_RatingBar = 16974521; // 0x10302b9
+    field public static final int Widget_Quantum_Light_RatingBar_Indicator = 16974522; // 0x10302ba
+    field public static final int Widget_Quantum_Light_RatingBar_Small = 16974523; // 0x10302bb
+    field public static final int Widget_Quantum_Light_ScrollView = 16974524; // 0x10302bc
+    field public static final int Widget_Quantum_Light_SeekBar = 16974525; // 0x10302bd
+    field public static final int Widget_Quantum_Light_SegmentedButton = 16974526; // 0x10302be
+    field public static final int Widget_Quantum_Light_Spinner = 16974528; // 0x10302c0
+    field public static final int Widget_Quantum_Light_StackView = 16974527; // 0x10302bf
+    field public static final int Widget_Quantum_Light_Tab = 16974529; // 0x10302c1
+    field public static final int Widget_Quantum_Light_TabWidget = 16974530; // 0x10302c2
+    field public static final int Widget_Quantum_Light_TextView = 16974531; // 0x10302c3
+    field public static final int Widget_Quantum_Light_TextView_SpinnerItem = 16974532; // 0x10302c4
+    field public static final int Widget_Quantum_Light_WebTextView = 16974533; // 0x10302c5
+    field public static final int Widget_Quantum_Light_WebView = 16974534; // 0x10302c6
+    field public static final int Widget_Quantum_ListPopupWindow = 16974448; // 0x1030270
+    field public static final int Widget_Quantum_ListView = 16974449; // 0x1030271
+    field public static final int Widget_Quantum_ListView_DropDown = 16974450; // 0x1030272
+    field public static final int Widget_Quantum_MediaRouteButton = 16974451; // 0x1030273
+    field public static final int Widget_Quantum_PopupMenu = 16974452; // 0x1030274
+    field public static final int Widget_Quantum_PopupMenu_Overflow = 16974453; // 0x1030275
+    field public static final int Widget_Quantum_PopupWindow = 16974454; // 0x1030276
+    field public static final int Widget_Quantum_ProgressBar = 16974455; // 0x1030277
+    field public static final int Widget_Quantum_ProgressBar_Horizontal = 16974456; // 0x1030278
+    field public static final int Widget_Quantum_ProgressBar_Large = 16974457; // 0x1030279
+    field public static final int Widget_Quantum_ProgressBar_Small = 16974458; // 0x103027a
+    field public static final int Widget_Quantum_ProgressBar_Small_Title = 16974459; // 0x103027b
+    field public static final int Widget_Quantum_RatingBar = 16974460; // 0x103027c
+    field public static final int Widget_Quantum_RatingBar_Indicator = 16974461; // 0x103027d
+    field public static final int Widget_Quantum_RatingBar_Small = 16974462; // 0x103027e
+    field public static final int Widget_Quantum_ScrollView = 16974463; // 0x103027f
+    field public static final int Widget_Quantum_SeekBar = 16974464; // 0x1030280
+    field public static final int Widget_Quantum_SegmentedButton = 16974465; // 0x1030281
+    field public static final int Widget_Quantum_Spinner = 16974467; // 0x1030283
+    field public static final int Widget_Quantum_StackView = 16974466; // 0x1030282
+    field public static final int Widget_Quantum_Tab = 16974468; // 0x1030284
+    field public static final int Widget_Quantum_TabWidget = 16974469; // 0x1030285
+    field public static final int Widget_Quantum_TextView = 16974470; // 0x1030286
+    field public static final int Widget_Quantum_TextView_SpinnerItem = 16974471; // 0x1030287
+    field public static final int Widget_Quantum_WebTextView = 16974472; // 0x1030288
+    field public static final int Widget_Quantum_WebView = 16974473; // 0x1030289
     field public static final int Widget_RatingBar = 16973857; // 0x1030021
     field public static final int Widget_ScrollView = 16973869; // 0x103002d
     field public static final int Widget_SeekBar = 16973856; // 0x1030020
@@ -3238,7 +3236,6 @@
     method public int getTaskId();
     method public final java.lang.CharSequence getTitle();
     method public final int getTitleColor();
-    method public android.app.VoiceInteractor getVoiceInteractor();
     method public final int getVolumeControlStream();
     method public android.view.Window getWindow();
     method public android.view.WindowManager getWindowManager();
@@ -3250,7 +3247,6 @@
     method public boolean isFinishing();
     method public boolean isImmersive();
     method public boolean isTaskRoot();
-    method public boolean isVoiceInteraction();
     method public final deprecated android.database.Cursor managedQuery(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
     method public boolean moveTaskToBack(boolean);
     method public boolean navigateUpTo(android.content.Intent);
@@ -4101,11 +4097,10 @@
     field public static final android.os.Parcelable.ClassLoaderCreator CREATOR;
   }
 
-  public class FragmentBreadCrumbs extends android.view.ViewGroup implements android.app.FragmentManager.OnBackStackChangedListener {
+  public deprecated class FragmentBreadCrumbs extends android.view.ViewGroup implements android.app.FragmentManager.OnBackStackChangedListener {
     ctor public FragmentBreadCrumbs(android.content.Context);
     ctor public FragmentBreadCrumbs(android.content.Context, android.util.AttributeSet);
     ctor public FragmentBreadCrumbs(android.content.Context, android.util.AttributeSet, int);
-    ctor public FragmentBreadCrumbs(android.content.Context, android.util.AttributeSet, int, int);
     method public void onBackStackChanged();
     method protected void onLayout(boolean, int, int, int, int);
     method public void setActivity(android.app.Activity);
@@ -4515,6 +4510,7 @@
     ctor public Notification.Action(int, java.lang.CharSequence, android.app.PendingIntent);
     method public android.app.Notification.Action clone();
     method public int describeContents();
+    method public android.os.Bundle getExtras();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public android.app.PendingIntent actionIntent;
@@ -4522,6 +4518,14 @@
     field public java.lang.CharSequence title;
   }
 
+  public static class Notification.Action.Builder {
+    ctor public Notification.Action.Builder(int, java.lang.CharSequence, android.app.PendingIntent);
+    ctor public Notification.Action.Builder(android.app.Notification.Action);
+    method public android.app.Notification.Action.Builder addExtras(android.os.Bundle);
+    method public android.app.Notification.Action build();
+    method public android.os.Bundle getExtras();
+  }
+
   public static class Notification.BigPictureStyle extends android.app.Notification.Style {
     ctor public Notification.BigPictureStyle();
     ctor public Notification.BigPictureStyle(android.app.Notification.Builder);
@@ -4542,6 +4546,7 @@
   public static class Notification.Builder {
     ctor public Notification.Builder(android.content.Context);
     method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
+    method public android.app.Notification.Builder addAction(android.app.Notification.Action);
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
     method public android.app.Notification.Builder addPerson(java.lang.String);
     method public android.app.Notification build();
@@ -4902,29 +4907,6 @@
     field public static final int MODE_NIGHT_YES = 2; // 0x2
   }
 
-  public class VoiceInteractor {
-    method public boolean submitRequest(android.app.VoiceInteractor.Request);
-    method public boolean[] supportsCommands(java.lang.String[]);
-  }
-
-  public static class VoiceInteractor.CommandRequest extends android.app.VoiceInteractor.Request {
-    ctor public VoiceInteractor.CommandRequest(java.lang.String, android.os.Bundle);
-    method public void onCommandResult(android.os.Bundle);
-  }
-
-  public static class VoiceInteractor.ConfirmationRequest extends android.app.VoiceInteractor.Request {
-    ctor public VoiceInteractor.ConfirmationRequest(java.lang.CharSequence, android.os.Bundle);
-    method public void onConfirmationResult(boolean, android.os.Bundle);
-  }
-
-  public static abstract class VoiceInteractor.Request {
-    ctor public VoiceInteractor.Request();
-    method public void cancel();
-    method public android.app.Activity getActivity();
-    method public android.content.Context getContext();
-    method public void onCancel();
-  }
-
   public final class WallpaperInfo implements android.os.Parcelable {
     ctor public WallpaperInfo(android.content.Context, android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
@@ -5235,7 +5217,7 @@
   public abstract class TaskService extends android.app.Service {
     ctor public TaskService();
     method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract void onStartTask(android.app.task.TaskParams);
+    method public abstract boolean onStartTask(android.app.task.TaskParams);
     method public abstract boolean onStopTask(android.app.task.TaskParams);
     method public final void taskFinished(android.app.task.TaskParams, boolean);
     field public static final java.lang.String PERMISSION_BIND = "android.permission.BIND_TASK_SERVICE";
@@ -7122,7 +7104,6 @@
     field public static final java.lang.String CATEGORY_TAB = "android.intent.category.TAB";
     field public static final java.lang.String CATEGORY_TEST = "android.intent.category.TEST";
     field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
-    field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
     field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
@@ -10088,7 +10069,7 @@
     enum_constant public static final android.graphics.Interpolator.Result NORMAL;
   }
 
-  public class LayerRasterizer extends android.graphics.Rasterizer {
+  public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
     ctor public LayerRasterizer();
     method public void addLayer(android.graphics.Paint, float, float);
     method public void addLayer(android.graphics.Paint);
@@ -10116,6 +10097,7 @@
     ctor public Matrix(android.graphics.Matrix);
     method public void getValues(float[]);
     method public boolean invert(android.graphics.Matrix);
+    method public boolean isAffine();
     method public boolean isIdentity();
     method public void mapPoints(float[], int, float[], int, int);
     method public void mapPoints(float[], float[]);
@@ -10213,7 +10195,9 @@
   public final class Outline {
     ctor public Outline();
     ctor public Outline(android.graphics.Outline);
+    method public boolean canClip();
     method public boolean isValid();
+    method public void reset();
     method public void set(android.graphics.Outline);
     method public void setConvexPath(android.graphics.Path);
     method public void setOval(int, int, int, int);
@@ -10247,7 +10231,7 @@
     method public int getHinting();
     method public android.graphics.MaskFilter getMaskFilter();
     method public android.graphics.PathEffect getPathEffect();
-    method public android.graphics.Rasterizer getRasterizer();
+    method public deprecated android.graphics.Rasterizer getRasterizer();
     method public android.graphics.Shader getShader();
     method public android.graphics.Paint.Cap getStrokeCap();
     method public android.graphics.Paint.Join getStrokeJoin();
@@ -10298,7 +10282,7 @@
     method public void setLinearText(boolean);
     method public android.graphics.MaskFilter setMaskFilter(android.graphics.MaskFilter);
     method public android.graphics.PathEffect setPathEffect(android.graphics.PathEffect);
-    method public android.graphics.Rasterizer setRasterizer(android.graphics.Rasterizer);
+    method public deprecated android.graphics.Rasterizer setRasterizer(android.graphics.Rasterizer);
     method public android.graphics.Shader setShader(android.graphics.Shader);
     method public void setShadowLayer(float, float, float, int);
     method public void setStrikeThruText(boolean);
@@ -10607,7 +10591,7 @@
     ctor public RadialGradient(float, float, float, int, int, android.graphics.Shader.TileMode);
   }
 
-  public class Rasterizer {
+  public deprecated class Rasterizer {
     ctor public Rasterizer();
   }
 
@@ -11355,6 +11339,24 @@
     method public android.graphics.pdf.PdfDocument.PageInfo.Builder setContentRect(android.graphics.Rect);
   }
 
+  public final class PdfRenderer implements java.lang.AutoCloseable {
+    ctor public PdfRenderer(android.os.ParcelFileDescriptor) throws java.io.IOException;
+    method public void close();
+    method public void closePage(android.graphics.pdf.PdfRenderer.Page);
+    method public int getPageCount();
+    method public android.graphics.pdf.PdfRenderer.Page openPage(int);
+    method public boolean shouldScaleForPrinting();
+  }
+
+  public final class PdfRenderer.Page {
+    method public int getHeight();
+    method public int getIndex();
+    method public int getWidth();
+    method public void render(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Matrix, int);
+    field public static final int RENDER_MODE_FOR_DISPLAY = 1; // 0x1
+    field public static final int RENDER_MODE_FOR_PRINT = 2; // 0x2
+  }
+
 }
 
 package android.hardware {
@@ -12277,12 +12279,16 @@
     field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MODE;
   }
 
+}
+
+package android.hardware.camera2.params {
+
   public final class ColorSpaceTransform {
-    ctor public ColorSpaceTransform(android.hardware.camera2.Rational[]);
+    ctor public ColorSpaceTransform(android.util.Rational[]);
     ctor public ColorSpaceTransform(int[]);
-    method public void copyElements(android.hardware.camera2.Rational[], int);
+    method public void copyElements(android.util.Rational[], int);
     method public void copyElements(int[], int);
-    method public android.hardware.camera2.Rational getElement(int, int);
+    method public android.util.Rational getElement(int, int);
   }
 
   public final class Face {
@@ -12302,7 +12308,7 @@
     method public int getColumnCount();
     method public float getGainFactor(int, int, int);
     method public int getGainFactorCount();
-    method public android.hardware.camera2.RggbChannelVector getGainFactorVector(int, int);
+    method public android.hardware.camera2.params.RggbChannelVector getGainFactorVector(int, int);
     method public int getRowCount();
     field public static final float MINIMUM_GAIN_FACTOR = 1.0f;
   }
@@ -12311,7 +12317,7 @@
     ctor public MeteringRectangle(int, int, int, int, int);
     ctor public MeteringRectangle(android.graphics.Point, android.util.Size, int);
     ctor public MeteringRectangle(android.graphics.Rect, int);
-    method public boolean equals(android.hardware.camera2.MeteringRectangle);
+    method public boolean equals(android.hardware.camera2.params.MeteringRectangle);
     method public int getHeight();
     method public int getMeteringWeight();
     method public android.graphics.Rect getRect();
@@ -12322,12 +12328,6 @@
     method public int getY();
   }
 
-  public final class Rational {
-    ctor public Rational(int, int);
-    method public int getDenominator();
-    method public int getNumerator();
-  }
-
   public final class RggbChannelVector {
     ctor public RggbChannelVector(float, float, float, float);
     method public void copyTo(float[], int);
@@ -12343,10 +12343,17 @@
     field public static final int RED = 0; // 0x0
   }
 
-  public final class Size {
-    ctor public Size(int, int);
-    method public final int getHeight();
-    method public final int getWidth();
+  public final class StreamConfigurationMap {
+    method public final int[] getOutputFormats();
+    method public long getOutputMinFrameDuration(int, android.util.Size);
+    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
+    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
+    method public android.util.Size[] getOutputSizes(int);
+    method public long getOutputStallDuration(int, android.util.Size);
+    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+    method public boolean isOutputSupportedFor(int);
+    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
+    method public boolean isOutputSupportedFor(android.view.Surface);
   }
 
   public final class TonemapCurve {
@@ -12363,23 +12370,6 @@
 
 }
 
-package android.hardware.camera2.params {
-
-  public final class StreamConfigurationMap {
-    method public final int[] getOutputFormats();
-    method public long getOutputMinFrameDuration(int, android.util.Size);
-    method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
-    method public android.util.Size[] getOutputSizes(java.lang.Class<T>);
-    method public android.util.Size[] getOutputSizes(int);
-    method public long getOutputStallDuration(int, android.util.Size);
-    method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
-    method public boolean isOutputSupportedFor(int);
-    method public static boolean isOutputSupportedFor(java.lang.Class<T>);
-    method public boolean isOutputSupportedFor(android.view.Surface);
-  }
-
-}
-
 package android.hardware.display {
 
   public final class DisplayManager {
@@ -12455,16 +12445,17 @@
     field public static final int MESSAGE_FEATURE_ABORT = 0; // 0x0
     field public static final int MESSAGE_GET_CEC_VERSION = 159; // 0x9f
     field public static final int MESSAGE_GET_MENU_LANGUAGE = 145; // 0x91
-    field public static final int MESSAGE_GET_OSD_NAME = 70; // 0x46
     field public static final int MESSAGE_GIVE_AUDIO_STATUS = 113; // 0x71
     field public static final int MESSAGE_GIVE_DECK_STATUS = 26; // 0x1a
     field public static final int MESSAGE_GIVE_DEVICE_POWER_STATUS = 143; // 0x8f
     field public static final int MESSAGE_GIVE_DEVICE_VENDOR_ID = 140; // 0x8c
+    field public static final int MESSAGE_GIVE_OSD_NAME = 70; // 0x46
     field public static final int MESSAGE_GIVE_PHYSICAL_ADDRESS = 131; // 0x83
     field public static final int MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS = 125; // 0x7d
     field public static final int MESSAGE_GIVE_TUNER_DEVICE_STATUS = 8; // 0x8
     field public static final int MESSAGE_IMAGE_VIEW_ON = 4; // 0x4
     field public static final int MESSAGE_INACTIVE_SOURCE = 157; // 0x9d
+    field public static final int MESSAGE_INITIATE_ARC = 192; // 0xc0
     field public static final int MESSAGE_MENU_REQUEST = 141; // 0x8d
     field public static final int MESSAGE_MENU_STATUS = 142; // 0x8e
     field public static final int MESSAGE_PLAY = 65; // 0x41
@@ -12472,10 +12463,14 @@
     field public static final int MESSAGE_RECORD_ON = 9; // 0x9
     field public static final int MESSAGE_RECORD_STATUS = 10; // 0xa
     field public static final int MESSAGE_RECORD_TV_SCREEN = 15; // 0xf
+    field public static final int MESSAGE_REPORT_ARC_INITIATED = 193; // 0xc1
+    field public static final int MESSAGE_REPORT_ARC_TERMINATED = 194; // 0xc2
     field public static final int MESSAGE_REPORT_AUDIO_STATUS = 122; // 0x7a
     field public static final int MESSAGE_REPORT_PHYSICAL_ADDRESS = 132; // 0x84
     field public static final int MESSAGE_REPORT_POWER_STATUS = 144; // 0x90
     field public static final int MESSAGE_REQUEST_ACTIVE_SOURCE = 133; // 0x85
+    field public static final int MESSAGE_REQUEST_ARC_INITIATION = 195; // 0xc3
+    field public static final int MESSAGE_REQUEST_ARC_TERMINATION = 196; // 0xc4
     field public static final int MESSAGE_ROUTING_CHANGE = 128; // 0x80
     field public static final int MESSAGE_ROUTING_INFORMATION = 129; // 0x81
     field public static final int MESSAGE_SELECT_ANALOG_SERVICE = 146; // 0x92
@@ -12493,6 +12488,7 @@
     field public static final int MESSAGE_STANDBY = 54; // 0x36
     field public static final int MESSAGE_SYSTEM_AUDIO_MODE_REQUEST = 112; // 0x70
     field public static final int MESSAGE_SYSTEM_AUDIO_MODE_STATUS = 126; // 0x7e
+    field public static final int MESSAGE_TERMINATE_ARC = 197; // 0xc5
     field public static final int MESSAGE_TEXT_VIEW_ON = 13; // 0xd
     field public static final int MESSAGE_TIMER_CLEARED_STATUS = 67; // 0x43
     field public static final int MESSAGE_TIMER_STATUS = 53; // 0x35
@@ -15546,7 +15542,7 @@
     method public void addCallback(android.media.session.Session.Callback);
     method public void addCallback(android.media.session.Session.Callback, android.os.Handler);
     method public void connect(android.media.session.RouteInfo, android.media.session.RouteOptions);
-    method public void disconnect(android.media.session.RouteInfo);
+    method public void disconnect();
     method public android.media.session.SessionToken getSessionToken();
     method public android.media.session.TransportPerformer getTransportPerformer();
     method public boolean isActive();
@@ -15556,6 +15552,11 @@
     method public void setActive(boolean);
     method public void setFlags(int);
     method public void setRouteOptions(java.util.List<android.media.session.RouteOptions>);
+    field public static final int DISCONNECT_REASON_PROVIDER_DISCONNECTED = 2; // 0x2
+    field public static final int DISCONNECT_REASON_ROUTE_CHANGED = 3; // 0x3
+    field public static final int DISCONNECT_REASON_SESSION_DESTROYED = 5; // 0x5
+    field public static final int DISCONNECT_REASON_SESSION_DISCONNECTED = 4; // 0x4
+    field public static final int DISCONNECT_REASON_USER_STOPPING = 1; // 0x1
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
@@ -19552,6 +19553,7 @@
   public class BatteryProperty implements android.os.Parcelable {
     method public int describeContents();
     method public int getInt();
+    method public long getLong();
     method public void readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CAPACITY = 4; // 0x4
@@ -19559,6 +19561,7 @@
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int CURRENT_AVERAGE = 3; // 0x3
     field public static final int CURRENT_NOW = 2; // 0x2
+    field public static final int ENERGY_COUNTER = 4; // 0x4
   }
 
   public class Binder implements android.os.IBinder {
@@ -25293,82 +25296,16 @@
 
   public class TrustAgentService extends android.app.Service {
     ctor public TrustAgentService();
-    method protected final void enableTrust(java.lang.String, long, boolean);
+    method public final void grantTrust(java.lang.CharSequence, long, boolean);
     method public final android.os.IBinder onBind(android.content.Intent);
-    method protected void onUnlockAttempt(boolean);
-    method protected final void revokeTrust();
+    method public void onUnlockAttempt(boolean);
+    method public final void revokeTrust();
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.trust.TrustAgentService";
     field public static final java.lang.String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
   }
 
 }
 
-package android.service.voice {
-
-  public class VoiceInteractionService extends android.app.Service {
-    ctor public VoiceInteractionService();
-    method public android.os.IBinder onBind(android.content.Intent);
-    method public void startSession(android.os.Bundle);
-    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";
-  }
-
-  public abstract class VoiceInteractionSession implements android.view.KeyEvent.Callback {
-    ctor public VoiceInteractionSession(android.content.Context);
-    ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
-    method public void finish();
-    method public android.view.LayoutInflater getLayoutInflater();
-    method public android.app.Dialog getWindow();
-    method public void hideWindow();
-    method public void onBackPressed();
-    method public abstract void onCancel(android.service.voice.VoiceInteractionSession.Request);
-    method public void onCloseSystemDialogs();
-    method public abstract void onCommand(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
-    method public void onComputeInsets(android.service.voice.VoiceInteractionSession.Insets);
-    method public abstract void onConfirm(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
-    method public void onCreate(android.os.Bundle);
-    method public android.view.View onCreateContentView();
-    method public void onDestroy();
-    method public abstract boolean[] onGetSupportedCommands(android.service.voice.VoiceInteractionSession.Caller, java.lang.String[]);
-    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 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 showWindow();
-    method public void startVoiceActivity(android.content.Intent);
-  }
-
-  public static class VoiceInteractionSession.Caller {
-  }
-
-  public static final class VoiceInteractionSession.Insets {
-    ctor public VoiceInteractionSession.Insets();
-    field public static final int TOUCHABLE_INSETS_CONTENT = 1; // 0x1
-    field public static final int TOUCHABLE_INSETS_FRAME = 0; // 0x0
-    field public static final int TOUCHABLE_INSETS_REGION = 3; // 0x3
-    field public int contentTopInsets;
-    field public int touchableInsets;
-    field public final android.graphics.Region touchableRegion;
-  }
-
-  public static class VoiceInteractionSession.Request {
-    method public void sendCancelResult();
-    method public void sendCommandResult(boolean, android.os.Bundle);
-    method public void sendConfirmResult(boolean, android.os.Bundle);
-  }
-
-  public abstract class VoiceInteractionSessionService extends android.app.Service {
-    ctor public VoiceInteractionSessionService();
-    method public android.os.IBinder onBind(android.content.Intent);
-    method public abstract android.service.voice.VoiceInteractionSession onNewSession(android.os.Bundle);
-  }
-
-}
-
 package android.service.wallpaper {
 
   public abstract class WallpaperService extends android.app.Service {
@@ -27080,6 +27017,7 @@
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
     method public boolean isNetworkRoaming();
     method public void listen(android.telephony.PhoneStateListener, int);
+    method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
     field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
     field public static final int CALL_STATE_IDLE = 0; // 0x0
@@ -29952,6 +29890,12 @@
     method public T getUpper();
   }
 
+  public final class Rational {
+    ctor public Rational(int, int);
+    method public int getDenominator();
+    method public int getNumerator();
+  }
+
   public final class Size {
     ctor public Size(int, int);
     method public int getHeight();
@@ -30790,6 +30734,7 @@
     field public static final int KEYCODE_P = 44; // 0x2c
     field public static final int KEYCODE_PAGE_DOWN = 93; // 0x5d
     field public static final int KEYCODE_PAGE_UP = 92; // 0x5c
+    field public static final int KEYCODE_PAIRING = 225; // 0xe1
     field public static final int KEYCODE_PERIOD = 56; // 0x38
     field public static final int KEYCODE_PICTSYMBOLS = 94; // 0x5e
     field public static final int KEYCODE_PLUS = 81; // 0x51
@@ -32552,8 +32497,10 @@
     method protected final int getForcedWindowFlags();
     method public abstract android.view.LayoutInflater getLayoutInflater();
     method protected final int getLocalFeatures();
+    method public abstract int getNavigationBarColor();
     method public android.transition.Transition getSharedElementEnterTransition();
     method public android.transition.Transition getSharedElementExitTransition();
+    method public abstract int getStatusBarColor();
     method public android.transition.TransitionManager getTransitionManager();
     method public abstract int getVolumeControlStream();
     method public android.view.WindowManager getWindowManager();
@@ -32605,9 +32552,11 @@
     method public void setLayout(int, int);
     method public void setLocalFocus(boolean, boolean);
     method public void setLogo(int);
+    method public abstract void setNavigationBarColor(int);
     method public void setSharedElementEnterTransition(android.transition.Transition);
     method public void setSharedElementExitTransition(android.transition.Transition);
     method public void setSoftInputMode(int);
+    method public abstract void setStatusBarColor(int);
     method public abstract void setTitle(java.lang.CharSequence);
     method public abstract deprecated void setTitleColor(int);
     method public void setTransitionManager(android.transition.TransitionManager);
@@ -32765,6 +32714,7 @@
     field public static final int FLAG_DIM_BEHIND = 2; // 0x2
     field public static final int FLAG_DISMISS_KEYGUARD = 4194304; // 0x400000
     field public static final deprecated int FLAG_DITHER = 4096; // 0x1000
+    field public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = -2147483648; // 0x80000000
     field public static final int FLAG_FORCE_NOT_FULLSCREEN = 2048; // 0x800
     field public static final int FLAG_FULLSCREEN = 1024; // 0x400
     field public static final int FLAG_HARDWARE_ACCELERATED = 16777216; // 0x1000000
@@ -36924,6 +36874,10 @@
     ctor public Toolbar(android.content.Context, android.util.AttributeSet);
     ctor public Toolbar(android.content.Context, android.util.AttributeSet, int);
     ctor public Toolbar(android.content.Context, android.util.AttributeSet, int, int);
+    method public int getContentInsetEnd();
+    method public int getContentInsetLeft();
+    method public int getContentInsetRight();
+    method public int getContentInsetStart();
     method public android.graphics.drawable.Drawable getLogo();
     method public java.lang.CharSequence getLogoDescription();
     method public android.view.Menu getMenu();
@@ -36932,6 +36886,8 @@
     method public java.lang.CharSequence getTitle();
     method public void inflateMenu(int);
     method protected void onLayout(boolean, int, int, int, int);
+    method public void setContentInsetsAbsolute(int, int);
+    method public void setContentInsetsRelative(int, int);
     method public void setLogo(int);
     method public void setLogo(android.graphics.drawable.Drawable);
     method public void setLogoDescription(int);
diff --git a/core/java/android/alsa/AlsaCardsParser.java b/core/java/android/alsa/AlsaCardsParser.java
index f9af979..8b44881 100644
--- a/core/java/android/alsa/AlsaCardsParser.java
+++ b/core/java/android/alsa/AlsaCardsParser.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.alsascan;
+package android.alsa;
 
 import android.util.Slog;
 import java.io.BufferedReader;
diff --git a/core/java/android/alsa/AlsaDevicesParser.java b/core/java/android/alsa/AlsaDevicesParser.java
index 094c8a2..82cc1ae 100644
--- a/core/java/android/alsa/AlsaDevicesParser.java
+++ b/core/java/android/alsa/AlsaDevicesParser.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.alsascan;
+package android.alsa;
 
 import android.util.Slog;
 import java.io.BufferedReader;
diff --git a/core/java/android/alsa/LineTokenizer.java b/core/java/android/alsa/LineTokenizer.java
index c138fc5..78c91b5 100644
--- a/core/java/android/alsa/LineTokenizer.java
+++ b/core/java/android/alsa/LineTokenizer.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.alsascan;
+package android.alsa;
 
 /**
  * @hide
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index cb00635..e1a94d7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1222,6 +1222,7 @@
      * Check whether this activity is running as part of a voice interaction with the user.
      * If true, it should perform its interaction with the user through the
      * {@link VoiceInteractor} returned by {@link #getVoiceInteractor}.
+     * @hide
      */
     public boolean isVoiceInteraction() {
         return mVoiceInteractor != null;
@@ -1230,6 +1231,7 @@
     /**
      * Retrieve the active {@link VoiceInteractor} that the user is going through to
      * interact with this activity.
+     * @hide
      */
     public VoiceInteractor getVoiceInteractor() {
         return mVoiceInteractor;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index d813dab..62c4f0f 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -19,6 +19,7 @@
 import android.Manifest;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.UserManager;
 import android.util.ArrayMap;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IAppOpsCallback;
@@ -412,6 +413,58 @@
     };
 
     /**
+     * Specifies whether an Op should be restricted by a user restriction.
+     * Each Op should be filled with a restriction string from UserManager or
+     * null to specify it is not affected by any user restriction.
+     */
+    private static String[] sOpRestrictions = new String[] {
+            null, //COARSE_LOCATION
+            null, //FINE_LOCATION
+            null, //GPS
+            null, //VIBRATE
+            null, //READ_CONTACTS
+            null, //WRITE_CONTACTS
+            null, //READ_CALL_LOG
+            null, //WRITE_CALL_LOG
+            null, //READ_CALENDAR
+            null, //WRITE_CALENDAR
+            null, //WIFI_SCAN
+            null, //POST_NOTIFICATION
+            null, //NEIGHBORING_CELLS
+            null, //CALL_PHONE
+            null, //READ_SMS
+            null, //WRITE_SMS
+            null, //RECEIVE_SMS
+            null, //RECEIVE_EMERGECY_SMS
+            null, //RECEIVE_MMS
+            null, //RECEIVE_WAP_PUSH
+            null, //SEND_SMS
+            null, //READ_ICC_SMS
+            null, //WRITE_ICC_SMS
+            null, //WRITE_SETTINGS
+            null, //SYSTEM_ALERT_WINDOW
+            null, //ACCESS_NOTIFICATIONS
+            null, //CAMERA
+            null, //RECORD_AUDIO
+            null, //PLAY_AUDIO
+            null, //READ_CLIPBOARD
+            null, //WRITE_CLIPBOARD
+            null, //TAKE_MEDIA_BUTTONS
+            null, //TAKE_AUDIO_FOCUS
+            null, //AUDIO_MASTER_VOLUME
+            null, //AUDIO_VOICE_VOLUME
+            null, //AUDIO_RING_VOLUME
+            null, //AUDIO_MEDIA_VOLUME
+            null, //AUDIO_ALARM_VOLUME
+            null, //AUDIO_NOTIFICATION_VOLUME
+            null, //AUDIO_BLUETOOTH_VOLUME
+            null, //WAKE_LOCK
+            null, //MONITOR_LOCATION
+            null, //MONITOR_HIGH_POWER_LOCATION
+            null, //GET_USAGE_STATS
+    };
+
+    /**
      * This specifies the default mode for each operation.
      */
     private static int[] sOpDefaultMode = new int[] {
@@ -542,6 +595,10 @@
             throw new IllegalStateException("sOpDisableReset length " + sOpDisableReset.length
                     + " should be " + _NUM_OP);
         }
+        if (sOpRestrictions.length != _NUM_OP) {
+            throw new IllegalStateException("sOpRestrictions length " + sOpRestrictions.length
+                    + " should be " + _NUM_OP);
+        }
         for (int i=0; i<_NUM_OP; i++) {
             if (sOpToString[i] != null) {
                 sOpStrToOp.put(sOpToString[i], i);
@@ -575,6 +632,14 @@
     }
 
     /**
+     * Retrieve the user restriction associated with an operation, or null if there is not one.
+     * @hide
+     */
+    public static String opToRestriction(int op) {
+        return sOpRestrictions[op];
+    }
+
+    /**
      * Retrieve the default mode for the operation.
      * @hide
      */
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index b4d8942..eeb5283 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1345,6 +1345,15 @@
     public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
             String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
             int initialCode, String initialData, Bundle initialExtras) {
+        sendOrderedBroadcastAsUser(intent, user, receiverPermission, AppOpsManager.OP_NONE,
+                resultReceiver, scheduler, initialCode, initialData, initialExtras);
+    }
+
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
         IIntentReceiver rd = null;
         if (resultReceiver != null) {
             if (mPackageInfo != null) {
diff --git a/core/java/android/app/FragmentBreadCrumbs.java b/core/java/android/app/FragmentBreadCrumbs.java
index e4de7af..ab0fc66 100644
--- a/core/java/android/app/FragmentBreadCrumbs.java
+++ b/core/java/android/app/FragmentBreadCrumbs.java
@@ -37,7 +37,10 @@
  *
  * <p>The default style for this view is
  * {@link android.R.style#Widget_FragmentBreadCrumbs}.
+ *
+ * @deprecated This widget is no longer supported.
  */
+@Deprecated
 public class FragmentBreadCrumbs extends ViewGroup
         implements FragmentManager.OnBackStackChangedListener {
     Activity mActivity;
@@ -88,6 +91,9 @@
         this(context, attrs, defStyleAttr, 0);
     }
 
+    /**
+     * @hide
+     */
     public FragmentBreadCrumbs(
             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 76a6a8e..fd76b9c4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -16,9 +16,6 @@
 
 package android.app;
 
-import com.android.internal.R;
-import com.android.internal.util.NotificationColorUtil;
-
 import android.annotation.IntDef;
 import android.content.Context;
 import android.content.Intent;
@@ -41,6 +38,9 @@
 import android.widget.ProgressBar;
 import android.widget.RemoteViews;
 
+import com.android.internal.R;
+import com.android.internal.util.NotificationColorUtil;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.text.NumberFormat;
@@ -134,7 +134,7 @@
      * leave it at its default value of 0.
      *
      * @see android.widget.ImageView#setImageLevel
-     * @see android.graphics.drawable#setLevel
+     * @see android.graphics.drawable.Drawable#setLevel
      */
     public int iconLevel;
 
@@ -700,10 +700,13 @@
      * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
      * selected by the user.
      * <p>
-     * Apps should use {@link Builder#addAction(int, CharSequence, PendingIntent)} to create and
-     * attach actions.
+     * Apps should use {@link Notification.Builder#addAction(int, CharSequence, PendingIntent)}
+     * or {@link Notification.Builder#addAction(Notification.Action)}
+     * to attach actions.
      */
     public static class Action implements Parcelable {
+        private final Bundle mExtras;
+
         /**
          * Small icon representing the action.
          */
@@ -717,22 +720,102 @@
          * may be rendered in a disabled presentation by the system UI.
          */
         public PendingIntent actionIntent;
- 
-        private Action() { }
+
         private Action(Parcel in) {
             icon = in.readInt();
             title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
             if (in.readInt() == 1) {
                 actionIntent = PendingIntent.CREATOR.createFromParcel(in);
             }
+            mExtras = in.readBundle();
         }
         /**
-         * Use {@link Builder#addAction(int, CharSequence, PendingIntent)}.
+         * Use {@link Notification.Builder#addAction(int, CharSequence, PendingIntent)}.
          */
         public Action(int icon, CharSequence title, PendingIntent intent) {
+            this(icon, title, intent, new Bundle());
+        }
+
+        private Action(int icon, CharSequence title, PendingIntent intent, Bundle extras) {
             this.icon = icon;
             this.title = title;
             this.actionIntent = intent;
+            this.mExtras = extras != null ? extras : new Bundle();
+        }
+
+        /**
+         * Get additional metadata carried around with this Action.
+         */
+        public Bundle getExtras() {
+            return mExtras;
+        }
+
+        /**
+         * Builder class for {@link Action} objects.
+         */
+        public static class Builder {
+            private final int mIcon;
+            private final CharSequence mTitle;
+            private final PendingIntent mIntent;
+            private final Bundle mExtras;
+
+            /**
+             * Construct a new builder for {@link Action} object.
+             * @param icon icon to show for this action
+             * @param title the title of the action
+             * @param intent the {@link PendingIntent} to fire when users trigger this action
+             */
+            public Builder(int icon, CharSequence title, PendingIntent intent) {
+                this(icon, title, intent, new Bundle());
+            }
+
+            /**
+             * Construct a new builder for {@link Action} object using the fields from an
+             * {@link Action}.
+             * @param action the action to read fields from.
+             */
+            public Builder(Action action) {
+                this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras));
+            }
+
+            private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras) {
+                mIcon = icon;
+                mTitle = title;
+                mIntent = intent;
+                mExtras = extras;
+            }
+
+            /**
+             * Merge additional metadata into this builder.
+             *
+             * <p>Values within the Bundle will replace existing extras values in this Builder.
+             *
+             * @see Notification.Action#extras
+             */
+            public Builder addExtras(Bundle extras) {
+                if (extras != null) {
+                    mExtras.putAll(extras);
+                }
+                return this;
+            }
+
+            /**
+             * Get the metadata Bundle used by this Builder.
+             *
+             * <p>The returned Bundle is shared with this Builder.
+             */
+            public Bundle getExtras() {
+                return mExtras;
+            }
+
+            /**
+             * Combine all of the options that have been set and return a new {@link Action}
+             * object.
+             * @return the built action
+             */
+            public Action build() {
+                return new Action(mIcon, mTitle, mIntent, mExtras);
+            }
         }
 
         @Override
@@ -740,8 +823,8 @@
             return new Action(
                 this.icon,
                 this.title,
-                this.actionIntent // safe to alias
-            );
+                this.actionIntent, // safe to alias
+                new Bundle(this.mExtras));
         }
         @Override
         public int describeContents() {
@@ -757,9 +840,10 @@
             } else {
                 out.writeInt(0);
             }
+            out.writeBundle(mExtras);
         }
-        public static final Parcelable.Creator<Action> CREATOR
-        = new Parcelable.Creator<Action>() {
+        public static final Parcelable.Creator<Action> CREATOR =
+                new Parcelable.Creator<Action>() {
             public Action createFromParcel(Parcel in) {
                 return new Action(in);
             }
@@ -1372,7 +1456,7 @@
         /**
          * Add a timestamp pertaining to the notification (usually the time the event occurred).
          * It will be shown in the notification content view by default; use
-         * {@link Builder#setShowWhen(boolean) setShowWhen} to control this.
+         * {@link #setShowWhen(boolean) setShowWhen} to control this.
          *
          * @see Notification#when
          */
@@ -1382,7 +1466,7 @@
         }
 
         /**
-         * Control whether the timestamp set with {@link Builder#setWhen(long) setWhen} is shown
+         * Control whether the timestamp set with {@link #setWhen(long) setWhen} is shown
          * in the content view.
          */
         public Builder setShowWhen(boolean show) {
@@ -1761,11 +1845,13 @@
          *
          * @see Notification#extras
          */
-        public Builder addExtras(Bundle bag) {
-            if (mExtras == null) {
-                mExtras = new Bundle(bag);
-            } else {
-                mExtras.putAll(bag);
+        public Builder addExtras(Bundle extras) {
+            if (extras != null) {
+                if (mExtras == null) {
+                    mExtras = new Bundle(extras);
+                } else {
+                    mExtras.putAll(extras);
+                }
             }
             return this;
         }
@@ -1782,8 +1868,8 @@
          *
          * @see Notification#extras
          */
-        public Builder setExtras(Bundle bag) {
-            mExtras = bag;
+        public Builder setExtras(Bundle extras) {
+            mExtras = extras;
             return this;
         }
 
@@ -1827,6 +1913,26 @@
         }
 
         /**
+         * Add an action to this notification. Actions are typically displayed by
+         * the system as a button adjacent to the notification content.
+         * <p>
+         * Every action must have an icon (32dp square and matching the
+         * <a href="{@docRoot}design/style/iconography.html#action-bar">Holo
+         * Dark action bar</a> visual style), a textual label, and a {@link PendingIntent}.
+         * <p>
+         * A notification in its expanded form can display up to 3 actions, from left to right in
+         * the order they were added. Actions will not be displayed when the notification is
+         * collapsed, however, so be sure that any essential functions may be accessed by the user
+         * in some other way (for example, in the Activity pointed to by {@link #contentIntent}).
+         *
+         * @param action The action to add.
+         */
+        public Builder addAction(Action action) {
+            mActions.add(action);
+            return this;
+        }
+
+        /**
          * Add a rich notification style to be applied at build time.
          *
          * @param style Object responsible for modifying the notification style.
@@ -1889,26 +1995,20 @@
             RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
             boolean showLine3 = false;
             boolean showLine2 = false;
-            int smallIconImageViewId = R.id.icon;
+
             if (mPriority < PRIORITY_LOW) {
                 // TODO: Low priority presentation
             }
             if (mLargeIcon != null) {
                 contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
                 processLargeIcon(mLargeIcon, contentView);
-                smallIconImageViewId = R.id.right_icon;
-            }
-            if (mSmallIcon != 0) {
-                contentView.setImageViewResource(smallIconImageViewId, mSmallIcon);
-                contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE);
-                if (mLargeIcon != null) {
-                    processSmallRightIcon(mSmallIcon, smallIconImageViewId, contentView);
-                } else {
-                    processSmallIconAsLarge(mSmallIcon, contentView);
-                }
-
-            } else {
-                contentView.setViewVisibility(smallIconImageViewId, View.GONE);
+                contentView.setImageViewResource(R.id.right_icon, mSmallIcon);
+                contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
+                processSmallRightIcon(mSmallIcon, contentView);
+            } else { // small icon at left
+                contentView.setImageViewResource(R.id.icon, mSmallIcon);
+                contentView.setViewVisibility(R.id.icon, View.VISIBLE);
+                processSmallIconAsLarge(mSmallIcon, contentView);
             }
             if (mContentTitle != null) {
                 contentView.setTextViewText(R.id.title, processLegacyText(mContentTitle));
@@ -2103,6 +2203,8 @@
         private void processLargeIcon(Bitmap largeIcon, RemoteViews contentView) {
             if (!isLegacy() || mColorUtil.isGrayscale(largeIcon)) {
                 applyLargeIconBackground(contentView);
+            } else {
+                removeLargeIconBackground(contentView);
             }
         }
 
@@ -2122,16 +2224,31 @@
                     -1);
         }
 
+        private void removeLargeIconBackground(RemoteViews contentView) {
+            contentView.setInt(R.id.icon, "setBackgroundResource", 0);
+        }
+
         /**
          * Recolor small icons when used in the R.id.right_icon slot.
          */
-        private void processSmallRightIcon(int smallIconDrawableId, int smallIconImageViewId,
+        private void processSmallRightIcon(int smallIconDrawableId,
                 RemoteViews contentView) {
             if (!isLegacy() || mColorUtil.isGrayscale(mContext, smallIconDrawableId)) {
-                contentView.setDrawableParameters(smallIconImageViewId, false, -1,
-                        mContext.getResources().getColor(
-                                R.color.notification_action_legacy_color_filter),
-                        PorterDuff.Mode.MULTIPLY, -1);
+                contentView.setDrawableParameters(R.id.right_icon, false, -1,
+                        0xFFFFFFFF,
+                        PorterDuff.Mode.SRC_ATOP, -1);
+
+                contentView.setInt(R.id.right_icon,
+                        "setBackgroundResource",
+                        R.drawable.notification_icon_legacy_bg);
+
+                contentView.setDrawableParameters(
+                        R.id.right_icon,
+                        true,
+                        -1,
+                        mColor,
+                        PorterDuff.Mode.SRC_ATOP,
+                        -1);
             }
         }
 
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 6dc48b0..4fcf7cd 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -34,6 +34,7 @@
 
 /**
  * Interface for an {@link Activity} to interact with the user through voice.
+ * @hide
  */
 public class VoiceInteractor {
     static final String TAG = "VoiceInteractor";
diff --git a/core/java/android/app/task/ITaskCallback.aidl b/core/java/android/app/task/ITaskCallback.aidl
index ffa57d1..d8a32fd 100644
--- a/core/java/android/app/task/ITaskCallback.aidl
+++ b/core/java/android/app/task/ITaskCallback.aidl
@@ -34,14 +34,17 @@
      * Immediate callback to the system after sending a start signal, used to quickly detect ANR.
      *
      * @param taskId Unique integer used to identify this task.
+     * @param ongoing True to indicate that the client is processing the task. False if the task is
+     * complete
      */
-    void acknowledgeStartMessage(int taskId);
+    void acknowledgeStartMessage(int taskId, boolean ongoing);
     /**
      * Immediate callback to the system after sending a stop signal, used to quickly detect ANR.
      *
      * @param taskId Unique integer used to identify this task.
+     * @param rescheulde Whether or not to reschedule this task.
      */
-    void acknowledgeStopMessage(int taskId);
+    void acknowledgeStopMessage(int taskId, boolean reschedule);
     /*
      * Tell the task manager that the client is done with its execution, so that it can go on to
      * the next one and stop attributing wakelock time to us etc.
diff --git a/core/java/android/app/task/TaskService.java b/core/java/android/app/task/TaskService.java
index 81333be..ab1a565 100644
--- a/core/java/android/app/task/TaskService.java
+++ b/core/java/android/app/task/TaskService.java
@@ -18,7 +18,6 @@
 
 import android.app.Service;
 import android.content.Intent;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -124,22 +123,20 @@
             switch (msg.what) {
                 case MSG_EXECUTE_TASK:
                     try {
-                        TaskService.this.onStartTask(params);
+                        boolean workOngoing = TaskService.this.onStartTask(params);
+                        ackStartMessage(params, workOngoing);
                     } catch (Exception e) {
                         Log.e(TAG, "Error while executing task: " + params.getTaskId());
                         throw new RuntimeException(e);
-                    } finally {
-                        maybeAckMessageReceived(params, MSG_EXECUTE_TASK);
                     }
                     break;
                 case MSG_STOP_TASK:
                     try {
-                        TaskService.this.onStopTask(params);
+                        boolean ret = TaskService.this.onStopTask(params);
+                        ackStopMessage(params, ret);
                     } catch (Exception e) {
                         Log.e(TAG, "Application unable to handle onStopTask.", e);
                         throw new RuntimeException(e);
-                    } finally {
-                        maybeAckMessageReceived(params, MSG_STOP_TASK);
                     }
                     break;
                 case MSG_TASK_FINISHED:
@@ -162,30 +159,34 @@
             }
         }
 
-        /**
-         * Messages come in on the application's main thread, so rather than run the risk of
-         * waiting for an app that may be doing something foolhardy, we ack to the system after
-         * processing a message. This allows us to throw up an ANR dialogue as quickly as possible.
-         * @param params id of the task we're acking.
-         * @param state Information about what message we're acking.
-         */
-        private void maybeAckMessageReceived(TaskParams params, int state) {
+        private void ackStartMessage(TaskParams params, boolean workOngoing) {
             final ITaskCallback callback = params.getCallback();
             final int taskId = params.getTaskId();
             if (callback != null) {
                 try {
-                    if (state == MSG_EXECUTE_TASK) {
-                        callback.acknowledgeStartMessage(taskId);
-                    } else if (state == MSG_STOP_TASK) {
-                        callback.acknowledgeStopMessage(taskId);
-                    }
+                     callback.acknowledgeStartMessage(taskId, workOngoing);
                 } catch(RemoteException e) {
                     Log.e(TAG, "System unreachable for starting task.");
                 }
             } else {
                 if (Log.isLoggable(TAG, Log.DEBUG)) {
-                    Log.d(TAG, state + ": Attempting to ack a task that has already been" +
-                            "processed.");
+                    Log.d(TAG, "Attempting to ack a task that has already been processed.");
+                }
+            }
+        }
+
+        private void ackStopMessage(TaskParams params, boolean reschedule) {
+            final ITaskCallback callback = params.getCallback();
+            final int taskId = params.getTaskId();
+            if (callback != null) {
+                try {
+                    callback.acknowledgeStopMessage(taskId, reschedule);
+                } catch(RemoteException e) {
+                    Log.e(TAG, "System unreachable for stopping task.");
+                }
+            } else {
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "Attempting to ack a task that has already been processed.");
                 }
             }
         }
@@ -203,12 +204,14 @@
      *
      * @param params Parameters specifying info about this task, including the extras bundle you
      *               optionally provided at task-creation time.
+     * @return True if your service needs to process the work (on a separate thread). False if
+     * there's no more work to be done for this task.
      */
-    public abstract void onStartTask(TaskParams params);
+    public abstract boolean onStartTask(TaskParams params);
 
     /**
-     * This method is called if your task should be stopped even before you've called
-     * {@link #taskFinished(TaskParams, boolean)}.
+     * This method is called if the system has determined that you must stop execution of your task
+     * even before you've had a chance to call {@link #taskFinished(TaskParams, boolean)}.
      *
      * <p>This will happen if the requirements specified at schedule time are no longer met. For
      * example you may have requested WiFi with
@@ -217,33 +220,27 @@
      * {@link android.content.Task.Builder#setRequiresDeviceIdle(boolean)}, and the phone left its
      * idle maintenance window. You are solely responsible for the behaviour of your application
      * upon receipt of this message; your app will likely start to misbehave if you ignore it. One
-     * repercussion is that the system will cease to hold a wakelock for you.</p>
-     *
-     * <p>After you've done your clean-up you are still expected to call
-     * {@link #taskFinished(TaskParams, boolean)} this will inform the TaskManager that all is well, and
-     * allow you to reschedule your task as it is probably uncompleted. Until you call
-     * taskFinished() you will not receive any newly scheduled tasks with the given task id as the
-     * TaskManager will consider the task to be in an error state.</p>
+     * immediate repercussion is that the system will cease holding a wakelock for you.</p>
      *
      * @param params Parameters specifying info about this task.
      * @return True to indicate to the TaskManager whether you'd like to reschedule this task based
-     * on the criteria provided at task creation-time. False to drop the task. Regardless of the
-     * value returned, your task must stop executing.
+     * on the retry criteria provided at task creation-time. False to drop the task. Regardless of
+     * the value returned, your task must stop executing.
      */
     public abstract boolean onStopTask(TaskParams params);
 
     /**
-     * Callback to inform the TaskManager you have completed execution. This can be called from any
+     * Callback to inform the TaskManager you've finished executing. This can be called from any
      * thread, as it will ultimately be run on your application's main thread. When the system
      * receives this message it will release the wakelock being held.
      * <p>
-     *     You can specify post-execution behaviour to the scheduler here with <code>needsReschedule
-     *     </code>. This will apply a back-off timer to your task based on the default, or what was
-     *     set with {@link android.content.Task.Builder#setBackoffCriteria(long, int)}. The
-     *     original requirements are always honoured even for a backed-off task.
-     *     Note that a task running in idle mode will not be backed-off. Instead what will happen
-     *     is the task will be re-added to the queue and re-executed within a future idle
-     *     maintenance window.
+     *     You can specify post-execution behaviour to the scheduler here with
+     *     <code>needsReschedule </code>. This will apply a back-off timer to your task based on
+     *     the default, or what was set with
+     *     {@link android.content.Task.Builder#setBackoffCriteria(long, int)}. The original
+     *     requirements are always honoured even for a backed-off task. Note that a task running in
+     *     idle mode will not be backed-off. Instead what will happen is the task will be re-added
+     *     to the queue and re-executed within a future idle maintenance window.
      * </p>
      *
      * @param params Parameters specifying system-provided info about this task, this was given to
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a059e48..a364e68 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1499,6 +1499,17 @@
             @Nullable  Bundle initialExtras);
 
     /**
+     * Similar to above but takes an appOp as well, to enforce restrictions.
+     * @see #sendOrderedBroadcastAsUser(Intent, UserHandle, String,
+     *       BroadcastReceiver, Handler, int, String, Bundle)
+     * @hide
+     */
+    public abstract void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            @Nullable String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+            @Nullable  Bundle initialExtras);
+
+    /**
      * Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
      * Intent you are sending stays around after the broadcast is complete,
      * so that others can quickly retrieve that data through the return
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 93f6cdf..c66355b 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -418,6 +418,16 @@
                 scheduler, initialCode, initialData, initialExtras);
     }
 
+    /** @hide */
+    @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, resultReceiver,
+                scheduler, initialCode, initialData, initialExtras);
+    }
+
     @Override
     public void sendStickyBroadcast(Intent intent) {
         mBase.sendStickyBroadcast(intent);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 076f657..fed63d2 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2809,6 +2809,7 @@
      * An activity that supports this category must be prepared to run with
      * no UI shown at all (though in some case it may have a UI shown), and
      * rely on {@link android.app.VoiceInteractor} to interact with the user.
+     * @hide
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_VOICE = "android.intent.category.VOICE";
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 499de17..1692a79 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1475,21 +1475,12 @@
          *               in length to {@code attrs} or {@code null}. All values
          *               must be of type {@link TypedValue#TYPE_ATTRIBUTE}.
          * @param attrs The desired attributes to be retrieved.
-         * @param defStyleAttr An attribute in the current theme that contains a
-         *                     reference to a style resource that supplies
-         *                     defaults values for the TypedArray.  Can be
-         *                     0 to not look for defaults.
-         * @param defStyleRes A resource identifier of a style resource that
-         *                    supplies default values for the TypedArray,
-         *                    used only if defStyleAttr is 0 or can not be found
-         *                    in the theme.  Can be 0 to not look for defaults.
          * @return Returns a TypedArray holding an array of the attribute
          *         values. Be sure to call {@link TypedArray#recycle()}
          *         when done with it.
          * @hide
          */
-        public TypedArray resolveAttributes(int[] values, int[] attrs,
-                int defStyleAttr, int defStyleRes) {
+        public TypedArray resolveAttributes(int[] values, int[] attrs) {
             final int len = attrs.length;
             if (values != null && len != values.length) {
                 throw new IllegalArgumentException(
@@ -1497,8 +1488,7 @@
             }
 
             final TypedArray array = TypedArray.obtain(Resources.this, len);
-            AssetManager.resolveAttrs(mTheme, defStyleAttr, defStyleRes,
-                    values, attrs, array.mData, array.mIndices);
+            AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
             array.mTheme = this;
             array.mXml = null;
 
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 15337ce..20dcf83 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -885,13 +885,13 @@
 
     /**
      * Extracts theme attributes from a typed array for later resolution using
-     * {@link Theme#resolveAttributes(int[], int[], int, int)}.
+     * {@link Theme#resolveAttributes(int[], int[])}. Removes the entries from
+     * the typed array so that subsequent calls to typed getters will return the
+     * default value without crashing.
      *
-     * @param array An array to populate with theme attributes. If the array is
-     *            null or not large enough, a new array will be returned.
      * @return an array of length {@link #getIndexCount()} populated with theme
-     *         attributes, or null if there are no theme attributes in the
-     *         typed array
+     *         attributes, or null if there are no theme attributes in the typed
+     *         array
      * @hide
      */
     public int[] extractThemeAttrs() {
@@ -901,15 +901,27 @@
 
         int[] attrs = null;
 
+        final int[] data = mData;
         final int N = length();
         for (int i = 0; i < N; i++) {
-            final int attrId = getThemeAttributeId(i, 0);
-            if (attrId != 0) {
-                if (attrs == null) {
-                    attrs = new int[N];
-                }
-                attrs[i] = attrId;
+            final int index = i * AssetManager.STYLE_NUM_ENTRIES;
+            if (data[index + AssetManager.STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
+                continue;
             }
+
+            // Null the entry so that we can safely call getZzz().
+            data[index + AssetManager.STYLE_TYPE] = TypedValue.TYPE_NULL;
+
+            final int attr = data[index + AssetManager.STYLE_DATA];
+            if (attr == 0) {
+                // This attribute is useless!
+                continue;
+            }
+
+            if (attrs == null) {
+                attrs = new int[N];
+            }
+            attrs[i] = attr;
         }
 
         return attrs;
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index 197e3ff..a75372f 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -42,12 +42,8 @@
 public class CursorWindow extends SQLiteClosable implements Parcelable {
     private static final String STATS_TAG = "CursorWindowStats";
 
-    /** The cursor window size. resource xml file specifies the value in kB.
-     * convert it to bytes here by multiplying with 1024.
-     */
-    private static final int sCursorWindowSize =
-        Resources.getSystem().getInteger(
-                com.android.internal.R.integer.config_cursorWindowSize) * 1024;
+    // This static member will be evaluated when first used.
+    private static int sCursorWindowSize = -1;
 
     /**
      * The native CursorWindow object pointer.  (FOR INTERNAL USE ONLY)
@@ -100,6 +96,13 @@
     public CursorWindow(String name) {
         mStartPos = 0;
         mName = name != null && name.length() != 0 ? name : "<unnamed>";
+        if (sCursorWindowSize < 0) {
+            /** The cursor window size. resource xml file specifies the value in kB.
+             * convert it to bytes here by multiplying with 1024.
+             */
+            sCursorWindowSize = Resources.getSystem().getInteger(
+                com.android.internal.R.integer.config_cursorWindowSize) * 1024;
+        }
         mWindowPtr = nativeCreate(mName, sCursorWindowSize);
         if (mWindowPtr == 0) {
             throw new CursorWindowAllocationException("Cursor window allocation of " +
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index b1c1005..1127fe5 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -17,6 +17,7 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.util.Rational;
 
 import java.util.Collections;
 import java.util.List;
@@ -316,8 +317,8 @@
      * <li>All non (0, 0) sizes will have non-zero widths and heights.</li>
      * </ul>
      */
-    public static final Key<android.hardware.camera2.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES =
-            new Key<android.hardware.camera2.Size[]>("android.jpeg.availableThumbnailSizes", android.hardware.camera2.Size[].class);
+    public static final Key<android.util.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES =
+            new Key<android.util.Size[]>("android.jpeg.availableThumbnailSizes", android.util.Size[].class);
 
     /**
      * <p>List of supported aperture
@@ -393,8 +394,8 @@
      * <p>The map should be on the order of 30-40 rows and columns, and
      * must be smaller than 64x64.</p>
      */
-    public static final Key<android.hardware.camera2.Size> LENS_INFO_SHADING_MAP_SIZE =
-            new Key<android.hardware.camera2.Size>("android.lens.info.shadingMapSize", android.hardware.camera2.Size.class);
+    public static final Key<android.util.Size> LENS_INFO_SHADING_MAP_SIZE =
+            new Key<android.util.Size>("android.lens.info.shadingMapSize", android.util.Size.class);
 
     /**
      * <p>The lens focus distance calibration quality.</p>
@@ -658,8 +659,8 @@
      * @hide
      */
     @Deprecated
-    public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_JPEG_SIZES =
-            new Key<android.hardware.camera2.Size[]>("android.scaler.availableJpegSizes", android.hardware.camera2.Size[].class);
+    public static final Key<android.util.Size[]> SCALER_AVAILABLE_JPEG_SIZES =
+            new Key<android.util.Size[]>("android.scaler.availableJpegSizes", android.util.Size[].class);
 
     /**
      * <p>The maximum ratio between active area width
@@ -704,8 +705,8 @@
      * @hide
      */
     @Deprecated
-    public static final Key<android.hardware.camera2.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
-            new Key<android.hardware.camera2.Size[]>("android.scaler.availableProcessedSizes", android.hardware.camera2.Size[].class);
+    public static final Key<android.util.Size[]> SCALER_AVAILABLE_PROCESSED_SIZES =
+            new Key<android.util.Size[]>("android.scaler.availableProcessedSizes", android.util.Size[].class);
 
     /**
      * <p>The mapping of image formats that are supported by this
@@ -961,9 +962,6 @@
      * can provide.</p>
      * <p>Please reference the documentation for the image data destination to
      * check if it limits the maximum size for image data.</p>
-     * <p>Not all output formats may be supported in a configuration with
-     * an input stream of a particular format. For more details, see
-     * android.scaler.availableInputOutputFormatsMap.</p>
      * <p>The following table describes the minimum required output stream
      * configurations based on the hardware level
      * ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel}):</p>
@@ -1106,8 +1104,8 @@
      * match this in
      * android.scaler.availableStreamConfigurations.</p>
      */
-    public static final Key<android.hardware.camera2.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE =
-            new Key<android.hardware.camera2.Size>("android.sensor.info.pixelArraySize", android.hardware.camera2.Size.class);
+    public static final Key<android.util.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE =
+            new Key<android.util.Size>("android.sensor.info.pixelArraySize", android.util.Size.class);
 
     /**
      * <p>Maximum raw value output by sensor.</p>
@@ -1515,13 +1513,4 @@
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
-
-
-
-
-
-
-
-
-
 }
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 8ae21f3..a70aa3b 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -19,6 +19,7 @@
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.Rational;
 import android.view.Surface;
 
 import java.util.HashSet;
@@ -169,7 +170,7 @@
      * @param in The parcel from which the object should be read
      * @hide
      */
-    public void readFromParcel(Parcel in) {
+    private void readFromParcel(Parcel in) {
         mSettings.readFromParcel(in);
 
         mSurfaceSet.clear();
@@ -965,8 +966,8 @@
      * <p>When a jpeg image capture is issued, the thumbnail size selected should have
      * the same aspect ratio as the jpeg image.</p>
      */
-    public static final Key<android.hardware.camera2.Size> JPEG_THUMBNAIL_SIZE =
-            new Key<android.hardware.camera2.Size>("android.jpeg.thumbnailSize", android.hardware.camera2.Size.class);
+    public static final Key<android.util.Size> JPEG_THUMBNAIL_SIZE =
+            new Key<android.util.Size>("android.jpeg.thumbnailSize", android.util.Size.class);
 
     /**
      * <p>The ratio of lens focal length to the effective
@@ -1518,12 +1519,4 @@
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
-
-
-
-
-
-
-
-
 }
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 0160622..d79f4b0 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -17,6 +17,8 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.params.Face;
+import android.util.Rational;
 
 /**
  * <p>The results of a single image capture from the image sensor.</p>
@@ -1512,8 +1514,8 @@
      * <p>When a jpeg image capture is issued, the thumbnail size selected should have
      * the same aspect ratio as the jpeg image.</p>
      */
-    public static final Key<android.hardware.camera2.Size> JPEG_THUMBNAIL_SIZE =
-            new Key<android.hardware.camera2.Size>("android.jpeg.thumbnailSize", android.hardware.camera2.Size.class);
+    public static final Key<android.util.Size> JPEG_THUMBNAIL_SIZE =
+            new Key<android.util.Size>("android.jpeg.thumbnailSize", android.util.Size.class);
 
     /**
      * <p>The ratio of lens focal length to the effective
@@ -2060,6 +2062,16 @@
             new Key<byte[]>("android.statistics.faceScores", byte[].class);
 
     /**
+     * <p>List of the faces detected through camera face detection
+     * in this result.</p>
+     * <p>Only available if {@link CaptureRequest#STATISTICS_FACE_DETECT_MODE android.statistics.faceDetectMode} <code>!=</code> OFF.</p>
+     *
+     * @see CaptureRequest#STATISTICS_FACE_DETECT_MODE
+     */
+    public static final Key<android.hardware.camera2.params.Face[]> STATISTICS_FACES =
+            new Key<android.hardware.camera2.params.Face[]>("android.statistics.faces", android.hardware.camera2.params.Face[].class);
+
+    /**
      * <p>The shading map is a low-resolution floating-point map
      * that lists the coefficients used to correct for vignetting, for each
      * Bayer color channel.</p>
@@ -2425,27 +2437,4 @@
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
-
-
-
-
-
-
-
-
-
-    /**
-     * <p>
-     * List of the {@link Face Faces} detected through camera face detection
-     * in this result.
-     * </p>
-     * <p>
-     * Only available if {@link #STATISTICS_FACE_DETECT_MODE} {@code !=}
-     * {@link CameraMetadata#STATISTICS_FACE_DETECT_MODE_OFF OFF}.
-     * </p>
-     *
-     * @see Face
-     */
-    public static final Key<Face[]> STATISTICS_FACES =
-            new Key<Face[]>("android.statistics.faces", Face[].class);
 }
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index a14d38b..caabed3 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -17,7 +17,7 @@
 package android.hardware.camera2;
 
 import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.CaptureResultExtras;
+import android.hardware.camera2.impl.CaptureResultExtras;
 
 /** @hide */
 interface ICameraDeviceCallbacks
diff --git a/core/java/android/hardware/camera2/Size.java b/core/java/android/hardware/camera2/Size.java
deleted file mode 100644
index 9328a003..0000000
--- a/core/java/android/hardware/camera2/Size.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-// TODO: Delete this class, since it was moved to android.util as public API
-
-/**
- * Immutable class for describing width and height dimensions in pixels.
- *
- * @hide
- */
-public final class Size {
-    /**
-     * Create a new immutable Size instance.
-     *
-     * @param width The width of the size, in pixels
-     * @param height The height of the size, in pixels
-     */
-    public Size(final int width, final int height) {
-        mWidth = width;
-        mHeight = height;
-    }
-
-    /**
-     * Get the width of the size (in pixels).
-     * @return width
-     */
-    public final int getWidth() {
-        return mWidth;
-    }
-
-    /**
-     * Get the height of the size (in pixels).
-     * @return height
-     */
-    public final int getHeight() {
-        return mHeight;
-    }
-
-    /**
-     * Check if this size is equal to another size.
-     * <p>
-     * Two sizes are equal if and only if both their widths and heights are
-     * equal.
-     * </p>
-     * <p>
-     * A size object is never equal to any other type of object.
-     * </p>
-     *
-     * @return {@code true} if the objects were equal, {@code false} otherwise
-     */
-    @Override
-    public boolean equals(final Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof Size) {
-            final Size other = (Size) obj;
-            return mWidth == other.mWidth && mHeight == other.mHeight;
-        }
-        return false;
-    }
-
-    /**
-     * Return the size represented as a string with the format {@code "WxH"}
-     *
-     * @return string representation of the size
-     */
-    @Override
-    public String toString() {
-        return mWidth + "x" + mHeight;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int hashCode() {
-        // assuming most sizes are <2^16, doing a rotate will give us perfect hashing
-        return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
-    }
-
-    private final int mWidth;
-    private final int mHeight;
-};
diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java
index 628d1c3..dba24a1 100644
--- a/core/java/android/hardware/camera2/impl/CameraDevice.java
+++ b/core/java/android/hardware/camera2/impl/CameraDevice.java
@@ -21,7 +21,6 @@
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.utils.CameraBinderDecorator;
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index d28f7bd..db7486d 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -22,7 +22,6 @@
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.Face;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
 import android.hardware.camera2.marshal.MarshalRegistry;
@@ -43,6 +42,7 @@
 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfiguration;
 import android.hardware.camera2.marshal.impl.MarshalQueryableStreamConfigurationDuration;
 import android.hardware.camera2.marshal.impl.MarshalQueryableString;
+import android.hardware.camera2.params.Face;
 import android.hardware.camera2.params.StreamConfiguration;
 import android.hardware.camera2.params.StreamConfigurationDuration;
 import android.hardware.camera2.params.StreamConfigurationMap;
diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.aidl b/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
similarity index 94%
rename from core/java/android/hardware/camera2/CaptureResultExtras.aidl
rename to core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
index 6587f02..ebc812a 100644
--- a/core/java/android/hardware/camera2/CaptureResultExtras.aidl
+++ b/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.impl;
 
 /** @hide */
 parcelable CaptureResultExtras;
diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.java b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java
similarity index 98%
rename from core/java/android/hardware/camera2/CaptureResultExtras.java
rename to core/java/android/hardware/camera2/impl/CaptureResultExtras.java
index e5c2c1c..b3a9559 100644
--- a/core/java/android/hardware/camera2/CaptureResultExtras.java
+++ b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.hardware.camera2;
+package android.hardware.camera2.impl;
 
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/hardware/camera2/marshal/MarshalHelpers.java b/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
index fd72ee2..35ecc2a 100644
--- a/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
+++ b/core/java/android/hardware/camera2/marshal/MarshalHelpers.java
@@ -18,8 +18,8 @@
 import static android.hardware.camera2.impl.CameraMetadataNative.*;
 import static com.android.internal.util.Preconditions.*;
 
-import android.hardware.camera2.Rational;
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.util.Rational;
 
 /**
  * Static functions in order to help implementing various marshaler functionality.
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
index d3796db..47f79bf 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableColorSpaceTransform.java
@@ -15,9 +15,9 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.ColorSpaceTransform;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.ColorSpaceTransform;
 import android.hardware.camera2.utils.TypeReference;
 
 import java.nio.ByteBuffer;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
index c8b9bd8..01780db 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableMeteringRectangle.java
@@ -15,9 +15,9 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.MeteringRectangle;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.MeteringRectangle;
 import android.hardware.camera2.utils.TypeReference;
 
 import java.nio.ByteBuffer;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
index 708da70..189b597 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryablePrimitive.java
@@ -15,11 +15,11 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.Rational;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
 import android.hardware.camera2.utils.TypeReference;
+import android.util.Rational;
 
 import static android.hardware.camera2.impl.CameraMetadataNative.*;
 import static android.hardware.camera2.marshal.MarshalHelpers.*;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
index 93c0e92..4253a0a 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableRggbChannelVector.java
@@ -15,9 +15,9 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.RggbChannelVector;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
+import android.hardware.camera2.params.RggbChannelVector;
 import android.hardware.camera2.utils.TypeReference;
 
 import java.nio.ByteBuffer;
diff --git a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
index 6a73bee..721644e 100644
--- a/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
+++ b/core/java/android/hardware/camera2/marshal/impl/MarshalQueryableSize.java
@@ -15,7 +15,7 @@
  */
 package android.hardware.camera2.marshal.impl;
 
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.marshal.Marshaler;
 import android.hardware.camera2.marshal.MarshalQueryable;
 import android.hardware.camera2.utils.TypeReference;
diff --git a/core/java/android/hardware/camera2/ColorSpaceTransform.java b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
similarity index 98%
rename from core/java/android/hardware/camera2/ColorSpaceTransform.java
rename to core/java/android/hardware/camera2/params/ColorSpaceTransform.java
index 5e4c0a2..fa8c8ea 100644
--- a/core/java/android/hardware/camera2/ColorSpaceTransform.java
+++ b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import static com.android.internal.util.Preconditions.*;
 
+import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.utils.HashCodeHelpers;
+import android.util.Rational;
 
 import java.util.Arrays;
 
diff --git a/core/java/android/hardware/camera2/Face.java b/core/java/android/hardware/camera2/params/Face.java
similarity index 97%
rename from core/java/android/hardware/camera2/Face.java
rename to core/java/android/hardware/camera2/params/Face.java
index ded8839d..2cd83a3 100644
--- a/core/java/android/hardware/camera2/Face.java
+++ b/core/java/android/hardware/camera2/params/Face.java
@@ -15,10 +15,13 @@
  */
 
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureResult;
 
 /**
  * Describes a face detected in an image.
diff --git a/core/java/android/hardware/camera2/LensShadingMap.java b/core/java/android/hardware/camera2/params/LensShadingMap.java
similarity index 97%
rename from core/java/android/hardware/camera2/LensShadingMap.java
rename to core/java/android/hardware/camera2/params/LensShadingMap.java
index 2b0108c..b328f578 100644
--- a/core/java/android/hardware/camera2/LensShadingMap.java
+++ b/core/java/android/hardware/camera2/params/LensShadingMap.java
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import static com.android.internal.util.Preconditions.*;
-import static android.hardware.camera2.RggbChannelVector.*;
+import static android.hardware.camera2.params.RggbChannelVector.*;
 
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.utils.HashCodeHelpers;
 
 import java.util.Arrays;
diff --git a/core/java/android/hardware/camera2/MeteringRectangle.java b/core/java/android/hardware/camera2/params/MeteringRectangle.java
similarity index 97%
rename from core/java/android/hardware/camera2/MeteringRectangle.java
rename to core/java/android/hardware/camera2/params/MeteringRectangle.java
index bb8e5b1..a26c57d 100644
--- a/core/java/android/hardware/camera2/MeteringRectangle.java
+++ b/core/java/android/hardware/camera2/params/MeteringRectangle.java
@@ -13,13 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import android.util.Size;
 import static com.android.internal.util.Preconditions.*;
 
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.utils.HashCodeHelpers;
 
 /**
diff --git a/core/java/android/hardware/camera2/RggbChannelVector.java b/core/java/android/hardware/camera2/params/RggbChannelVector.java
similarity index 99%
rename from core/java/android/hardware/camera2/RggbChannelVector.java
rename to core/java/android/hardware/camera2/params/RggbChannelVector.java
index 80167c6..30591f6 100644
--- a/core/java/android/hardware/camera2/RggbChannelVector.java
+++ b/core/java/android/hardware/camera2/params/RggbChannelVector.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import static com.android.internal.util.Preconditions.*;
 
diff --git a/core/java/android/hardware/camera2/TonemapCurve.java b/core/java/android/hardware/camera2/params/TonemapCurve.java
similarity index 97%
rename from core/java/android/hardware/camera2/TonemapCurve.java
rename to core/java/android/hardware/camera2/params/TonemapCurve.java
index 2958ebf..0fcffac 100644
--- a/core/java/android/hardware/camera2/TonemapCurve.java
+++ b/core/java/android/hardware/camera2/params/TonemapCurve.java
@@ -14,11 +14,15 @@
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+package android.hardware.camera2.params;
 
 import static com.android.internal.util.Preconditions.*;
 
 import android.graphics.PointF;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraMetadata;
+import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.utils.HashCodeHelpers;
 
 import java.util.Arrays;
diff --git a/core/java/android/hardware/hdmi/HdmiCec.java b/core/java/android/hardware/hdmi/HdmiCec.java
index 7213c78..9193f89 100644
--- a/core/java/android/hardware/hdmi/HdmiCec.java
+++ b/core/java/android/hardware/hdmi/HdmiCec.java
@@ -120,7 +120,7 @@
     public static final int MESSAGE_TIMER_CLEARED_STATUS = 0x043;
     public static final int MESSAGE_USER_CONTROL_PRESSED = 0x44;
     public static final int MESSAGE_USER_CONTROL_RELEASED = 0x45;
-    public static final int MESSAGE_GET_OSD_NAME = 0x46;
+    public static final int MESSAGE_GIVE_OSD_NAME = 0x46;
     public static final int MESSAGE_SET_OSD_NAME = 0x47;
     public static final int MESSAGE_SET_OSD_STRING = 0x64;
     public static final int MESSAGE_SET_TIMER_PROGRAM_TITLE = 0x67;
@@ -158,6 +158,12 @@
     public static final int MESSAGE_VENDOR_COMMAND_WITH_ID = 0xA0;
     public static final int MESSAGE_CLEAR_EXTERNAL_TIMER = 0xA1;
     public static final int MESSAGE_SET_EXTERNAL_TIMER = 0xA2;
+    public static final int MESSAGE_INITIATE_ARC = 0xC0;
+    public static final int MESSAGE_REPORT_ARC_INITIATED = 0xC1;
+    public static final int MESSAGE_REPORT_ARC_TERMINATED = 0xC2;
+    public static final int MESSAGE_REQUEST_ARC_INITIATION = 0xC3;
+    public static final int MESSAGE_REQUEST_ARC_TERMINATION = 0xC4;
+    public static final int MESSAGE_TERMINATE_ARC = 0xC5;
     public static final int MESSAGE_ABORT = 0xFF;
 
     public static final int UNKNOWN_VENDOR_ID = 0xFFFFFF;
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 0a09fcb..489b8a5 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -89,7 +89,6 @@
     }
 
     public LinkProperties() {
-        clear();
     }
 
     // copy constructor instead of clone
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 4b85398..c2b06a2 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -66,6 +66,7 @@
     private AsyncChannel mAsyncChannel;
     private final String LOG_TAG;
     private static final boolean DBG = true;
+    private static final boolean VDBG = true;
     // TODO - this class shouldn't cache data or it runs the risk of getting out of sync
     // Make the API require each of these when any is updated so we have the data we need,
     // without caching.
@@ -266,11 +267,14 @@
      */
     private void evalScores() {
         if (mConnectionRequested) {
+            if (VDBG) log("evalScores - already trying - size=" + mNetworkRequests.size());
             // already trying
             return;
         }
+        if (VDBG) log("evalScores!");
         for (int i=0; i < mNetworkRequests.size(); i++) {
             int score = mNetworkRequests.valueAt(i).score;
+            if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore);
             if (score < mNetworkScore) {
                 // have a request that has a lower scored network servicing it
                 // (or no network) than we could provide, so lets connect!
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index f339e52..32050dc 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -146,9 +146,9 @@
                 return null;
         }
 
-        BatteryProperty prop = new BatteryProperty(Integer.MIN_VALUE);
+        BatteryProperty prop = new BatteryProperty();
         if ((mBatteryPropertiesRegistrar.getProperty(id, prop) == 0) &&
-            (prop.getInt() != Integer.MIN_VALUE))
+            (prop.getLong() != Long.MIN_VALUE))
             return prop;
         else
             return null;
diff --git a/core/java/android/os/BatteryProperty.java b/core/java/android/os/BatteryProperty.java
index ec73952..0ed856e 100644
--- a/core/java/android/os/BatteryProperty.java
+++ b/core/java/android/os/BatteryProperty.java
@@ -53,20 +53,18 @@
      */
     public static final int CAPACITY = 4;
 
-    private int mValueInt;
-
     /**
-     * @hide
+     * Battery remaining energy in nanowatt-hours, as a long integer.
      */
-    public BatteryProperty(int value) {
-        mValueInt = value;
-    }
+    public static final int ENERGY_COUNTER = 4;
+
+    private long mValueLong;
 
     /**
      * @hide
      */
     public BatteryProperty() {
-        mValueInt = Integer.MIN_VALUE;
+        mValueLong = Long.MIN_VALUE;
     }
 
     /**
@@ -79,9 +77,21 @@
      * @return The queried property value, or Integer.MIN_VALUE if not supported.
      */
     public int getInt() {
-        return mValueInt;
+        return (int)mValueLong;
     }
 
+    /**
+     * Return the value of a property of long type previously queried
+     * via {@link BatteryManager#getProperty
+     * BatteryManager.getProperty()}.  If the platform does
+     * not provide the property queried, this value will be
+     * Long.MIN_VALUE.
+     *
+     * @return The queried property value, or Long.MIN_VALUE if not supported.
+     */
+    public long getLong() {
+        return mValueLong;
+    }
     /*
      * Parcel read/write code must be kept in sync with
      * frameworks/native/services/batteryservice/BatteryProperty.cpp
@@ -92,11 +102,11 @@
     }
 
     public void readFromParcel(Parcel p) {
-        mValueInt = p.readInt();
+        mValueLong = p.readLong();
     }
 
     public void writeToParcel(Parcel p, int flags) {
-        p.writeInt(mValueInt);
+        p.writeLong(mValueLong);
     }
 
     public static final Parcelable.Creator<BatteryProperty> CREATOR
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 4857533..af45fa0 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -31,7 +31,6 @@
 import android.text.format.DateFormat;
 import android.util.Printer;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import com.android.internal.os.BatterySipper;
@@ -532,7 +531,8 @@
 
     public final static class HistoryItem implements Parcelable {
         public HistoryItem next;
-        
+
+        // The time of this event in milliseconds, as per SystemClock.elapsedRealtime().
         public long time;
 
         public static final byte CMD_UPDATE = 0;        // These can be written as deltas
@@ -601,6 +601,7 @@
         public int states;
 
         public static final int STATE2_VIDEO_ON_FLAG = 1<<0;
+        public static final int STATE2_LOW_POWER_FLAG = 1<<1;
         public int states2;
 
         // The wake lock that was acquired at this point.
@@ -622,8 +623,11 @@
         public static final int EVENT_TOP = 0x0003;
         // Event is about an application package that is at the top of the screen.
         public static final int EVENT_SYNC = 0x0004;
+        // Events for all additional wake locks aquired/release within a wake block.
+        // These are not generated by default.
+        public static final int EVENT_WAKE_LOCK = 0x0005;
         // Number of event types.
-        public static final int EVENT_COUNT = 0x0005;
+        public static final int EVENT_COUNT = 0x0006;
         // Mask to extract out only the type part of the event.
         public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
 
@@ -635,12 +639,14 @@
         public static final int EVENT_TOP_FINISH = EVENT_TOP | EVENT_FLAG_FINISH;
         public static final int EVENT_SYNC_START = EVENT_SYNC | EVENT_FLAG_START;
         public static final int EVENT_SYNC_FINISH = EVENT_SYNC | EVENT_FLAG_FINISH;
+        public static final int EVENT_WAKE_LOCK_START = EVENT_WAKE_LOCK | EVENT_FLAG_START;
+        public static final int EVENT_WAKE_LOCK_FINISH = EVENT_WAKE_LOCK | EVENT_FLAG_FINISH;
 
         // For CMD_EVENT.
         public int eventCode;
         public HistoryTag eventTag;
 
-        // Only set for CMD_CURRENT_TIME.
+        // Only set for CMD_CURRENT_TIME or CMD_RESET, as per System.currentTimeMillis().
         public long currentTime;
 
         // Meta-data when reading.
@@ -887,6 +893,11 @@
             return true;
         }
 
+        public void removeEvents(int code) {
+            int idx = code&HistoryItem.EVENT_TYPE_MASK;
+            mActiveEvents[idx] = null;
+        }
+
         public HashMap<String, SparseIntArray> getStateForEvent(int code) {
             return mActiveEvents[code];
         }
@@ -997,6 +1008,21 @@
             long elapsedRealtimeUs, int which);
 
     /**
+     * Returns the time in microseconds that low power mode has been enabled while the device was
+     * running on battery.
+     *
+     * {@hide}
+     */
+    public abstract long getLowPowerModeEnabledTime(long elapsedRealtimeUs, int which);
+
+    /**
+     * Returns the number of times that low power mode was enabled.
+     *
+     * {@hide}
+     */
+    public abstract int getLowPowerModeEnabledCount(int which);
+
+    /**
      * Returns the time in microseconds that the phone has been on while the device was
      * running on battery.
      * 
@@ -1157,14 +1183,15 @@
     public static final BitDescription[] HISTORY_STATE2_DESCRIPTIONS
             = new BitDescription[] {
         new BitDescription(HistoryItem.STATE2_VIDEO_ON_FLAG, "video", "v"),
+        new BitDescription(HistoryItem.STATE2_LOW_POWER_FLAG, "low_power", "lp"),
     };
 
     public static final String[] HISTORY_EVENT_NAMES = new String[] {
-            "null", "proc", "fg", "top", "sync"
+            "null", "proc", "fg", "top", "sync", "wake_lock_in"
     };
 
     public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
-            "Enl", "Epr", "Efg", "Etp", "Esy"
+            "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl"
     };
 
     /**
@@ -1630,11 +1657,12 @@
         final long totalUptime = computeUptime(rawUptime, which);
         final long screenOnTime = getScreenOnTime(rawRealtime, which);
         final long interactiveTime = getInteractiveTime(rawRealtime, which);
+        final long lowPowerModeEnabledTime = getLowPowerModeEnabledTime(rawRealtime, which);
         final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
         final long wifiOnTime = getWifiOnTime(rawRealtime, which);
         final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
         final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which);
-       
+
         StringBuilder sb = new StringBuilder(128);
         
         SparseArray<? extends Uid> uidStats = getUidStats();
@@ -1699,7 +1727,8 @@
                 mobileRxTotalBytes, mobileTxTotalBytes, wifiRxTotalBytes, wifiTxTotalBytes,
                 fullWakeLockTimeTotal, partialWakeLockTimeTotal,
                 0 /*legacy input event count*/, getMobileRadioActiveTime(rawRealtime, which),
-                getMobileRadioActiveAdjustedTime(which), interactiveTime / 1000);
+                getMobileRadioActiveAdjustedTime(which), interactiveTime / 1000,
+                lowPowerModeEnabledTime / 1000);
         
         // Dump screen brightness stats
         Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS];
@@ -2092,32 +2121,20 @@
 
         final long screenOnTime = getScreenOnTime(rawRealtime, which);
         final long interactiveTime = getInteractiveTime(rawRealtime, which);
+        final long lowPowerModeEnabledTime = getLowPowerModeEnabledTime(rawRealtime, which);
         final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
         final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
         final long wifiOnTime = getWifiOnTime(rawRealtime, which);
         final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which);
         sb.setLength(0);
         sb.append(prefix);
-                sb.append("  Interactive: "); formatTimeMs(sb, interactiveTime / 1000);
-                sb.append("("); sb.append(formatRatioLocked(interactiveTime, whichBatteryRealtime));
-                sb.append(")");
-        pw.println(sb.toString());
-        sb.setLength(0);
-        sb.append(prefix);
                 sb.append("  Screen on: "); formatTimeMs(sb, screenOnTime / 1000);
                 sb.append("("); sb.append(formatRatioLocked(screenOnTime, whichBatteryRealtime));
                 sb.append(") "); sb.append(getScreenOnCount(which));
-                sb.append("x, Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000);
-                sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
+                sb.append("x, Interactive: "); formatTimeMs(sb, interactiveTime / 1000);
+                sb.append("("); sb.append(formatRatioLocked(interactiveTime, whichBatteryRealtime));
                 sb.append(")");
         pw.println(sb.toString());
-        if (phoneOnTime != 0) {
-            sb.setLength(0);
-            sb.append(prefix);
-                    sb.append("  Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000);
-                    sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
-                    sb.append(") "); sb.append(getPhoneOnCount(which));
-        }
         sb.setLength(0);
         sb.append(prefix);
         sb.append("  Screen brightnesses:");
@@ -2139,7 +2156,24 @@
         }
         if (!didOne) sb.append(" (no activity)");
         pw.println(sb.toString());
-        
+        if (lowPowerModeEnabledTime != 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+                    sb.append("  Low power mode enabled: ");
+                    formatTimeMs(sb, lowPowerModeEnabledTime / 1000);
+                    sb.append("(");
+                    sb.append(formatRatioLocked(lowPowerModeEnabledTime, whichBatteryRealtime));
+                    sb.append(")");
+            pw.println(sb.toString());
+        }
+        if (phoneOnTime != 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+                    sb.append("  Active phone call: "); formatTimeMs(sb, phoneOnTime / 1000);
+                    sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
+                    sb.append(") "); sb.append(getPhoneOnCount(which));
+        }
+
         // Calculate wakelock times across all uids.
         long fullWakeLockTimeTotalMicros = 0;
         long partialWakeLockTimeTotalMicros = 0;
@@ -3004,6 +3038,8 @@
                 pw.print(rec.numReadInts);
                 pw.print(") ");
             } else {
+                pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                pw.print(HISTORY_DATA); pw.print(',');
                 if (lastTime < 0) {
                     pw.print(rec.time - baseTime);
                 } else {
@@ -3190,6 +3226,7 @@
                 }
                 pw.println();
                 oldState = rec.states;
+                oldState2 = rec.states2;
             }
         }
     }
@@ -3266,21 +3303,25 @@
                     if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
                             || rec.cmd == HistoryItem.CMD_RESET) {
                         printed = true;
+                        hprinter.printNextItem(pw, rec, baseTime, checkin,
+                                (flags&DUMP_VERBOSE) != 0);
+                        rec.cmd = HistoryItem.CMD_UPDATE;
                     } else if (rec.currentTime != 0) {
                         printed = true;
                         byte cmd = rec.cmd;
                         rec.cmd = HistoryItem.CMD_CURRENT_TIME;
-                        if (checkin) {
-                            pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
-                            pw.print(HISTORY_DATA); pw.print(',');
-                        }
                         hprinter.printNextItem(pw, rec, baseTime, checkin,
                                 (flags&DUMP_VERBOSE) != 0);
                         rec.cmd = cmd;
                     }
                     if (tracker != null) {
-                        int oldCode = rec.eventCode;
-                        HistoryTag oldTag = rec.eventTag;
+                        if (rec.cmd != HistoryItem.CMD_UPDATE) {
+                            hprinter.printNextItem(pw, rec, baseTime, checkin,
+                                    (flags&DUMP_VERBOSE) != 0);
+                            rec.cmd = HistoryItem.CMD_UPDATE;
+                        }
+                        int oldEventCode = rec.eventCode;
+                        HistoryTag oldEventTag = rec.eventTag;
                         rec.eventTag = new HistoryTag();
                         for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
                             HashMap<String, SparseIntArray> active
@@ -3296,24 +3337,18 @@
                                     rec.eventTag.string = ent.getKey();
                                     rec.eventTag.uid = uids.keyAt(j);
                                     rec.eventTag.poolIdx = uids.valueAt(j);
-                                    if (checkin) {
-                                        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
-                                        pw.print(HISTORY_DATA); pw.print(',');
-                                    }
                                     hprinter.printNextItem(pw, rec, baseTime, checkin,
                                             (flags&DUMP_VERBOSE) != 0);
+                                    rec.wakeReasonTag = null;
+                                    rec.wakelockTag = null;
                                 }
                             }
                         }
-                        rec.eventCode = oldCode;
-                        rec.eventTag = oldTag;
+                        rec.eventCode = oldEventCode;
+                        rec.eventTag = oldEventTag;
                         tracker = null;
                     }
                 }
-                if (checkin) {
-                    pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
-                    pw.print(HISTORY_DATA); pw.print(',');
-                }
                 hprinter.printNextItem(pw, rec, baseTime, checkin,
                         (flags&DUMP_VERBOSE) != 0);
             } else if (rec.eventCode != HistoryItem.EVENT_NONE) {
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index cb3d528..69b828f 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -55,6 +55,14 @@
      */
     public abstract void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis);
 
+    public abstract boolean getLowPowerModeEnabled();
+
+    public interface LowPowerModeListener {
+        public void onLowPowerModeChanged(boolean enabled);
+    }
+
+    public abstract void registerLowPowerModeObserver(LowPowerModeListener listener);
+
     // TODO: Remove this and retrieve as a local service instead.
     public abstract void setPolicy(WindowManagerPolicy policy);
 }
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 29f2545..39cb826 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -66,7 +66,7 @@
     }
 
     public VolumePreference(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
+        this(context, attrs, com.android.internal.R.attr.dialogPreferenceStyle);
     }
 
     public void setStreamType(int streamType) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 89f4388..cd28085 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -769,6 +769,28 @@
     public static final String
             ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
 
+    /**
+     * Activity Action: Show Device Name Settings.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you safeguard
+     * against this.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String DEVICE_NAME_SETTINGS = "android.settings.DEVICE_NAME";
+
+    /**
+     * Activity Action: Show pairing settings.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you safeguard
+     * against this.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_PAIRING_SETTINGS = "android.settings.PAIRING_SETTINGS";
+
     // End of Intent actions for Settings
 
     /**
@@ -2889,6 +2911,7 @@
             MOVED_TO_GLOBAL.add(Settings.Global.SET_GLOBAL_HTTP_PROXY);
             MOVED_TO_GLOBAL.add(Settings.Global.DEFAULT_DNS_SERVER);
             MOVED_TO_GLOBAL.add(Settings.Global.PREFERRED_NETWORK_MODE);
+            MOVED_TO_GLOBAL.add(Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY);
         }
 
         /** @hide */
@@ -5319,6 +5342,13 @@
         */
        public static final String USE_GOOGLE_MAIL = "use_google_mail";
 
+        /**
+         * Webview Data reduction proxy key.
+         * @hide
+         */
+        public static final String WEBVIEW_DATA_REDUCTION_PROXY_KEY =
+                "webview_data_reduction_proxy_key";
+
        /**
         * Whether Wifi display is enabled/disabled
         * 0=disabled. 1=enabled.
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index a94f45a..e2e9ff4 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -16,9 +16,11 @@
 
 package android.service.notification;
 
+import android.annotation.PrivateApi;
 import android.annotation.SdkConstant;
 import android.app.INotificationManager;
 import android.app.Service;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.os.IBinder;
@@ -26,9 +28,6 @@
 import android.os.ServiceManager;
 import android.util.Log;
 
-import java.util.Comparator;
-import java.util.HashMap;
-
 /**
  * A service that receives calls from the system when new notifications are posted or removed.
  * <p>To extend this class, you must declare the service in your manifest file with
@@ -53,6 +52,9 @@
 
     private INotificationManager mNoMan;
 
+    /** Only valid after a successful call to (@link registerAsService}. */
+    private int mCurrentUser;
+
     /**
      * The {@link Intent} that must be declared as handled by the service.
      */
@@ -267,6 +269,42 @@
         return true;
     }
 
+    /**
+     * Directly register this service with the Notification Manager.
+     *
+     * <p>Only system services may use this call. It will fail for non-system callers.
+     * Apps should ask the user to add their listener in Settings.
+     *
+     * @param componentName the component that will consume the notification information
+     * @param currentUser the user to use as the stream filter
+     * @hide
+     */
+    @PrivateApi
+    public void registerAsSystemService(ComponentName componentName, int currentUser)
+            throws RemoteException {
+        if (mWrapper == null) {
+            mWrapper = new INotificationListenerWrapper();
+        }
+        INotificationManager noMan = getNotificationInterface();
+        noMan.registerListener(mWrapper, componentName, currentUser);
+        mCurrentUser = currentUser;
+    }
+
+    /**
+     * Directly unregister this service from the Notification Manager.
+     *
+     * <P>This method will fail for listeners that were not registered
+     * with (@link registerAsService).
+     * @hide
+     */
+    @PrivateApi
+    public void unregisterAsSystemService() throws RemoteException {
+        if (mWrapper != null) {
+            INotificationManager noMan = getNotificationInterface();
+            noMan.unregisterListener(mWrapper, mCurrentUser);
+        }
+    }
+
     private class INotificationListenerWrapper extends INotificationListener.Stub {
         @Override
         public void onNotificationPosted(StatusBarNotification sbn,
diff --git a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
index c346771..9e4c2bf 100644
--- a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
+++ b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
@@ -23,6 +23,6 @@
  * @hide
  */
 oneway interface ITrustAgentServiceCallback {
-    void enableTrust(String message, long durationMs, boolean initiatedByUser);
+    void grantTrust(CharSequence message, long durationMs, boolean initiatedByUser);
     void revokeTrust();
 }
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index d5ce429..bb40eec 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -29,12 +29,12 @@
  * to be trusted.
  *
  * <p>To extend this class, you must declare the service in your manifest file with
- * the {@link android.Manifest.permission#BIND_TRUST_AGENT_SERVICE} permission
+ * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission
  * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
  * <pre>
  * &lt;service android:name=".TrustAgent"
  *          android:label="&#64;string/service_name"
- *          android:permission="android.permission.BIND_TRUST_AGENT_SERVICE">
+ *          android:permission="android.permission.BIND_TRUST_AGENT">
  *     &lt;intent-filter>
  *         &lt;action android:name="android.service.trust.TrustAgentService" />
  *     &lt;/intent-filter>
@@ -47,7 +47,7 @@
  * {@link android.R.styleable#TrustAgent}. For example:</p>
  *
  * <pre>
- * &lt;trust_agent xmlns:android="http://schemas.android.com/apk/res/android"
+ * &lt;trust-agent xmlns:android="http://schemas.android.com/apk/res/android"
  *          android:settingsActivity=".TrustAgentSettings" /></pre>
  */
 public class TrustAgentService extends Service {
@@ -88,7 +88,7 @@
      *
      * @param successful true if the attempt succeeded
      */
-    protected void onUnlockAttempt(boolean successful) {
+    public void onUnlockAttempt(boolean successful) {
     }
 
     private void onError(String msg) {
@@ -96,7 +96,7 @@
     }
 
     /**
-     * Call to enable trust on the device.
+     * Call to grant trust on the device.
      *
      * @param message describes why the device is trusted, e.g. "Trusted by location".
      * @param durationMs amount of time in milliseconds to keep the device in a trusted state. Trust
@@ -104,10 +104,10 @@
      * @param initiatedByUser indicates that the user has explicitly initiated an action that proves
      *                        the user is about to use the device.
      */
-    protected final void enableTrust(String message, long durationMs, boolean initiatedByUser) {
+    public final void grantTrust(CharSequence message, long durationMs, boolean initiatedByUser) {
         if (mCallback != null) {
             try {
-                mCallback.enableTrust(message, durationMs, initiatedByUser);
+                mCallback.grantTrust(message.toString(), durationMs, initiatedByUser);
             } catch (RemoteException e) {
                 onError("calling enableTrust()");
             }
@@ -117,7 +117,7 @@
     /**
      * Call to revoke trust on the device.
      */
-    protected final void revokeTrust() {
+    public final void revokeTrust() {
         if (mCallback != null) {
             try {
                 mCallback.revokeTrust();
diff --git a/core/java/android/service/voice/package.html b/core/java/android/service/voice/package.html
new file mode 100644
index 0000000..1c9bf9d
--- /dev/null
+++ b/core/java/android/service/voice/package.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+    {@hide}
+</body>
+</html>
diff --git a/core/java/android/hardware/camera2/Rational.java b/core/java/android/util/Rational.java
similarity index 92%
rename from core/java/android/hardware/camera2/Rational.java
rename to core/java/android/util/Rational.java
index 693ee2b..8d4c67f 100644
--- a/core/java/android/hardware/camera2/Rational.java
+++ b/core/java/android/util/Rational.java
@@ -13,11 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.hardware.camera2;
+package android.util;
 
 /**
- * The rational data type used by CameraMetadata keys. Contains a pair of ints representing the
- * numerator and denominator of a Rational number. This type is immutable.
+ * <p>An immutable data type representation a rational number.</p>
+ *
+ * <p>Contains a pair of {@code int}s representing the numerator and denominator of a
+ * Rational number. </p>
  */
 public final class Rational {
     private final int mNumerator;
@@ -30,7 +32,9 @@
      * is always positive.</p>
      *
      * <p>A rational value with a 0-denominator may be constructed, but will have similar semantics
-     * as float NaN and INF values. The int getter functions return 0 in this case.</p>
+     * as float {@code NaN} and {@code INF} values. For {@code NaN},
+     * both {@link #getNumerator} and {@link #getDenominator} functions will return 0. For
+     * positive or negative {@code INF}, only the {@link #getDenominator} will return 0.</p>
      *
      * @param numerator the numerator of the rational
      * @param denominator the denominator of the rational
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 7b49006..9601a8d 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -1220,10 +1220,6 @@
     }
 
     private RenderNode buildDisplayList(View view, HardwareCanvas canvas) {
-        if (mDrawDelta <= 0) {
-            return view.mRenderNode;
-        }
-
         view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
                 == View.PFLAG_INVALIDATED;
         view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 852fce5..b8e1b89 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -639,8 +639,13 @@
      * Wakes up the device.  Behaves somewhat like {@link #KEYCODE_POWER} but it
      * has no effect if the device is already awake. */
     public static final int KEYCODE_WAKEUP          = 224;
+    /** Key code constant: Pairing key.
+     * Initiates peripheral pairing mode. Useful for pairing remote control
+     * devices or game controllers, especially if no other input mode is
+     * available. */
+    public static final int KEYCODE_PAIRING         = 225;
 
-    private static final int LAST_KEYCODE = KEYCODE_WAKEUP;
+    private static final int LAST_KEYCODE = KEYCODE_PAIRING;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index 0cfde94..b2839cb 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -387,6 +387,10 @@
         nSetClipToOutline(mNativeRenderNode, clipToOutline);
     }
 
+    public boolean getClipToOutline() {
+        return nGetClipToOutline(mNativeRenderNode);
+    }
+
     /**
      * Controls the RenderNode's circular reveal clip.
      */
@@ -919,6 +923,7 @@
     private static native void nSetAnimationMatrix(long renderNode, long animationMatrix);
 
     private static native boolean nHasOverlappingRendering(long renderNode);
+    private static native boolean nGetClipToOutline(long renderNode);
     private static native float nGetAlpha(long renderNode);
     private static native float nGetLeft(long renderNode);
     private static native float nGetTop(long renderNode);
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index ec4d560..c1a4fee 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -16,12 +16,12 @@
 
 package android.view;
 
+import android.animation.Animator;
 import android.animation.TimeInterpolator;
 import android.graphics.Canvas;
 import android.graphics.CanvasProperty;
 import android.graphics.Paint;
 import android.util.SparseIntArray;
-import android.util.TimeUtils;
 
 import com.android.internal.util.VirtualRefBasePtr;
 import com.android.internal.view.animation.FallbackLUTInterpolator;
@@ -29,12 +29,12 @@
 import com.android.internal.view.animation.NativeInterpolatorFactory;
 
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 
 /**
  * @hide
  */
-public final class RenderNodeAnimator {
-
+public final class RenderNodeAnimator extends Animator {
     // Keep in sync with enum RenderProperty in Animator.h
     public static final int TRANSLATION_X = 0;
     public static final int TRANSLATION_Y = 1;
@@ -51,6 +51,11 @@
 
     // Keep in sync with enum PaintFields in Animator.h
     public static final int PAINT_STROKE_WIDTH = 0;
+
+    /**
+     * Field for the Paint alpha channel, which should be specified as a value
+     * between 0 and 255.
+     */
     public static final int PAINT_ALPHA = 1;
 
     // ViewPropertyAnimator uses a mask for its values, we need to remap them
@@ -72,36 +77,42 @@
         put(ViewPropertyAnimator.ALPHA, ALPHA);
     }};
 
-    // Keep in sync DeltaValueType in Animator.h
-    public static final int DELTA_TYPE_ABSOLUTE = 0;
-    public static final int DELTA_TYPE_DELTA = 1;
-
     private VirtualRefBasePtr mNativePtr;
 
     private RenderNode mTarget;
+    private View mViewTarget;
     private TimeInterpolator mInterpolator;
+
     private boolean mStarted = false;
+    private boolean mFinished = false;
 
     public int mapViewPropertyToRenderProperty(int viewProperty) {
         return sViewPropertyAnimatorMap.get(viewProperty);
     }
 
-    public RenderNodeAnimator(int property, int deltaType, float deltaValue) {
+    public RenderNodeAnimator(int property, float finalValue) {
         init(nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
-                property, deltaType, deltaValue));
+                property, finalValue));
     }
 
-    public RenderNodeAnimator(CanvasProperty<Float> property, int deltaType, float deltaValue) {
+    public RenderNodeAnimator(CanvasProperty<Float> property, float finalValue) {
         init(nCreateCanvasPropertyFloatAnimator(
                 new WeakReference<RenderNodeAnimator>(this),
-                property.getNativeContainer(), deltaType, deltaValue));
+                property.getNativeContainer(), finalValue));
     }
 
-    public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField,
-            int deltaType, float deltaValue) {
+    /**
+     * Creates a new render node animator for a field on a Paint property.
+     *
+     * @param property The paint property to target
+     * @param paintField Paint field to animate, one of {@link #PAINT_ALPHA} or
+     *            {@link #PAINT_STROKE_WIDTH}
+     * @param finalValue The target value for the property
+     */
+    public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField, float finalValue) {
         init(nCreateCanvasPropertyPaintAnimator(
                 new WeakReference<RenderNodeAnimator>(this),
-                property.getNativeContainer(), paintField, deltaType, deltaValue));
+                property.getNativeContainer(), paintField, finalValue));
     }
 
     private void init(long ptr) {
@@ -121,56 +132,139 @@
         if (mInterpolator.getClass().isAnnotationPresent(HasNativeInterpolator.class)) {
             ni = ((NativeInterpolatorFactory)mInterpolator).createNativeInterpolator();
         } else {
-            int duration = nGetDuration(mNativePtr.get());
+            long duration = nGetDuration(mNativePtr.get());
             ni = FallbackLUTInterpolator.createNativeInterpolator(mInterpolator, duration);
         }
         nSetInterpolator(mNativePtr.get(), ni);
     }
 
-    private void start(RenderNode node) {
+    @Override
+    public void start() {
+        if (mTarget == null) {
+            throw new IllegalStateException("Missing target!");
+        }
+
         if (mStarted) {
             throw new IllegalStateException("Already started!");
         }
+
         mStarted = true;
         applyInterpolator();
-        mTarget = node;
         mTarget.addAnimator(this);
+
+        final ArrayList<AnimatorListener> listeners = getListeners();
+        final int numListeners = listeners == null ? 0 : listeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            listeners.get(i).onAnimationStart(this);
+        }
+
+        if (mViewTarget != null) {
+            // Kick off a frame to start the process
+            mViewTarget.invalidateViewProperty(true, false);
+        }
     }
 
-    public void start(View target) {
-        start(target.mRenderNode);
-        // Kick off a frame to start the process
-        target.invalidateViewProperty(true, false);
+    @Override
+    public void cancel() {
+        mTarget.removeAnimator(this);
+
+        final ArrayList<AnimatorListener> listeners = getListeners();
+        final int numListeners = listeners == null ? 0 : listeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            listeners.get(i).onAnimationCancel(this);
+        }
     }
 
-    public void start(Canvas canvas) {
+    @Override
+    public void end() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void pause() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void resume() {
+        throw new UnsupportedOperationException();
+    }
+
+    public void setTarget(View view) {
+        mViewTarget = view;
+        mTarget = view.mRenderNode;
+    }
+
+    public void setTarget(Canvas canvas) {
         if (!(canvas instanceof GLES20RecordingCanvas)) {
             throw new IllegalArgumentException("Not a GLES20RecordingCanvas");
         }
-        GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
-        start(recordingCanvas.mNode);
+
+        final GLES20RecordingCanvas recordingCanvas = (GLES20RecordingCanvas) canvas;
+        setTarget(recordingCanvas.mNode);
     }
 
-    public void cancel() {
-        mTarget.removeAnimator(this);
+    public void setTarget(RenderNode node) {
+        mViewTarget = null;
+        mTarget = node;
     }
 
-    public void setDuration(int duration) {
+    public RenderNode getTarget() {
+        return mTarget;
+    }
+
+    @Override
+    public void setStartDelay(long startDelay) {
+        checkMutable();
+        nSetStartDelay(mNativePtr.get(), startDelay);
+    }
+
+    @Override
+    public long getStartDelay() {
+        return nGetStartDelay(mNativePtr.get());
+    }
+
+    @Override
+    public RenderNodeAnimator setDuration(long duration) {
         checkMutable();
         nSetDuration(mNativePtr.get(), duration);
+        return this;
     }
 
+    @Override
+    public long getDuration() {
+        return nGetDuration(mNativePtr.get());
+    }
+
+    @Override
+    public boolean isRunning() {
+        return mStarted && !mFinished;
+    }
+
+    @Override
     public void setInterpolator(TimeInterpolator interpolator) {
         checkMutable();
         mInterpolator = interpolator;
     }
 
-    long getNativeAnimator() {
-        return mNativePtr.get();
+    @Override
+    public TimeInterpolator getInterpolator() {
+        return mInterpolator;
     }
 
     private void onFinished() {
+        mFinished = true;
         mTarget.removeAnimator(this);
+
+        final ArrayList<AnimatorListener> listeners = getListeners();
+        final int numListeners = listeners == null ? 0 : listeners.size();
+        for (int i = 0; i < numListeners; i++) {
+            listeners.get(i).onAnimationEnd(this);
+        }
+    }
+
+    long getNativeAnimator() {
+        return mNativePtr.get();
     }
 
     // Called by native
@@ -182,12 +276,14 @@
     }
 
     private static native long nCreateAnimator(WeakReference<RenderNodeAnimator> weakThis,
-            int property, int deltaValueType, float deltaValue);
+            int property, float deltaValue);
     private static native long nCreateCanvasPropertyFloatAnimator(WeakReference<RenderNodeAnimator> weakThis,
-            long canvasProperty, int deltaValueType, float deltaValue);
+            long canvasProperty, float deltaValue);
     private static native long nCreateCanvasPropertyPaintAnimator(WeakReference<RenderNodeAnimator> weakThis,
-            long canvasProperty, int paintField, int deltaValueType, float deltaValue);
-    private static native void nSetDuration(long nativePtr, int duration);
-    private static native int nGetDuration(long nativePtr);
+            long canvasProperty, int paintField, float deltaValue);
+    private static native void nSetDuration(long nativePtr, long duration);
+    private static native long nGetDuration(long nativePtr);
+    private static native void nSetStartDelay(long nativePtr, long startDelay);
+    private static native long nGetStartDelay(long nativePtr);
     private static native void nSetInterpolator(long animPtr, long interpolatorPtr);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ab518d9..fb7d57d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2774,8 +2774,15 @@
 
     /**
      * @hide
+     *
+     * Makes system ui transparent.
      */
-    public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x0000FFFF;
+    public static final int SYSTEM_UI_TRANSPARENT = 0x00008000;
+
+    /**
+     * @hide
+     */
+    public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00007FFF;
 
     /**
      * These are the system UI flags that can be cleared by events outside
@@ -4767,8 +4774,8 @@
                 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this);
             }
 
-            manageFocusHotspot(true, oldFocus);
             onFocusChanged(true, direction, previouslyFocusedRect);
+            manageFocusHotspot(true, oldFocus);
             refreshDrawableState();
         }
     }
@@ -6745,6 +6752,24 @@
     }
 
     /**
+     * Sets the pressed state for this view and provides a touch coordinate for
+     * animation hinting.
+     *
+     * @param pressed Pass true to set the View's internal state to "pressed",
+     *            or false to reverts the View's internal state from a
+     *            previously set "pressed" state.
+     * @param x The x coordinate of the touch that caused the press
+     * @param y The y coordinate of the touch that caused the press
+     */
+    private void setPressed(boolean pressed, float x, float y) {
+        if (pressed) {
+            setHotspot(R.attr.state_pressed, x, y);
+        }
+
+        setPressed(pressed);
+    }
+
+    /**
      * Sets the pressed state for this view.
      *
      * @see #isClickable()
@@ -6762,6 +6787,10 @@
             mPrivateFlags &= ~PFLAG_PRESSED;
         }
 
+        if (!pressed) {
+            clearHotspot(R.attr.state_pressed);
+        }
+
         if (needsRefresh) {
             refreshDrawableState();
         }
@@ -8986,7 +9015,6 @@
 
         if ((viewFlags & ENABLED_MASK) == DISABLED) {
             if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
-                clearHotspot(R.attr.state_pressed);
                 setPressed(false);
             }
             // A disabled view that is clickable still consumes the touch
@@ -9019,8 +9047,7 @@
                             // showed it as pressed.  Make it show the pressed
                             // state now (before scheduling the click) to ensure
                             // the user sees it.
-                            setHotspot(R.attr.state_pressed, x, y);
-                            setPressed(true);
+                            setPressed(true, x, y);
                        }
 
                         if (!mHasPerformedLongPress) {
@@ -9054,8 +9081,6 @@
                         }
 
                         removeTapCallback();
-                    } else {
-                        clearHotspot(R.attr.state_pressed);
                     }
                     break;
 
@@ -9168,7 +9193,6 @@
      */
     private void removeUnsetPressCallback() {
         if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) {
-            clearHotspot(R.attr.state_pressed);
             setPressed(false);
             removeCallbacks(mUnsetPressedState);
         }
@@ -10699,9 +10723,16 @@
         mRenderNode.setOutline(mOutline);
     }
 
-    // TODO: remove
-    public final boolean getClipToOutline() { return false; }
-    public void setClipToOutline(boolean clipToOutline) {}
+    public final boolean getClipToOutline() {
+        return mRenderNode.getClipToOutline();
+    }
+
+    public void setClipToOutline(boolean clipToOutline) {
+        // TODO: add a fast invalidation here
+        if (getClipToOutline() != clipToOutline) {
+            mRenderNode.setClipToOutline(clipToOutline);
+        }
+    }
 
     private void queryOutlineFromBackgroundIfUndefined() {
         if ((mPrivateFlags3 & PFLAG3_OUTLINE_DEFINED) == 0) {
@@ -10710,7 +10741,7 @@
                 mOutline = new Outline();
             } else {
                 //invalidate outline, to ensure background calculates it
-                mOutline.set(null);
+                mOutline.reset();
             }
             if (mBackground.getOutline(mOutline)) {
                 if (!mOutline.isValid()) {
@@ -19220,8 +19251,7 @@
         @Override
         public void run() {
             mPrivateFlags &= ~PFLAG_PREPRESSED;
-            setHotspot(R.attr.state_pressed, x, y);
-            setPressed(true);
+            setPressed(true, x, y);
             checkForLongClick(ViewConfiguration.getTapTimeout());
         }
     }
@@ -19502,7 +19532,6 @@
     private final class UnsetPressedState implements Runnable {
         @Override
         public void run() {
-            clearHotspot(R.attr.state_pressed);
             setPressed(false);
         }
     }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9b09d85..35b4bc5 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -668,6 +668,11 @@
     public void detachFunctor(long functor) {
         // TODO: Make the resize buffer some other way to not need this block
         mBlockResizeBuffer = true;
+        if (mAttachInfo.mHardwareRenderer != null) {
+            // Fence so that any pending invokeFunctor() messages will be processed
+            // before we return from detachFunctor.
+            mAttachInfo.mHardwareRenderer.fence();
+        }
     }
 
     public boolean invokeFunctor(long functor, boolean waitForCompletion) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 375f5e3..ecc4586 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -642,9 +642,7 @@
         final WindowManager.LayoutParams attrs = getAttributes();
         attrs.width = width;
         attrs.height = height;
-        if (mCallback != null) {
-            mCallback.onWindowAttributesChanged(attrs);
-        }
+        dispatchWindowAttributesChanged(attrs);
     }
 
     /**
@@ -661,9 +659,7 @@
     {
         final WindowManager.LayoutParams attrs = getAttributes();
         attrs.gravity = gravity;
-        if (mCallback != null) {
-            mCallback.onWindowAttributesChanged(attrs);
-        }
+        dispatchWindowAttributesChanged(attrs);
     }
 
     /**
@@ -675,9 +671,7 @@
     public void setType(int type) {
         final WindowManager.LayoutParams attrs = getAttributes();
         attrs.type = type;
-        if (mCallback != null) {
-            mCallback.onWindowAttributesChanged(attrs);
-        }
+        dispatchWindowAttributesChanged(attrs);
     }
 
     /**
@@ -700,9 +694,7 @@
             attrs.format = mDefaultWindowFormat;
             mHaveWindowFormat = false;
         }
-        if (mCallback != null) {
-            mCallback.onWindowAttributesChanged(attrs);
-        }
+        dispatchWindowAttributesChanged(attrs);
     }
 
     /**
@@ -715,9 +707,7 @@
     public void setWindowAnimations(int resId) {
         final WindowManager.LayoutParams attrs = getAttributes();
         attrs.windowAnimations = resId;
-        if (mCallback != null) {
-            mCallback.onWindowAttributesChanged(attrs);
-        }
+        dispatchWindowAttributesChanged(attrs);
     }
 
     /**
@@ -735,9 +725,7 @@
         } else {
             mHasSoftInputMode = false;
         }
-        if (mCallback != null) {
-            mCallback.onWindowAttributesChanged(attrs);
-        }
+        dispatchWindowAttributesChanged(attrs);
     }
     
     /**
@@ -793,14 +781,19 @@
             attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY;
         }
         mForcedWindowFlags |= mask;
-        if (mCallback != null) {
-            mCallback.onWindowAttributesChanged(attrs);
-        }
+        dispatchWindowAttributesChanged(attrs);
     }
 
     private void setPrivateFlags(int flags, int mask) {
         final WindowManager.LayoutParams attrs = getAttributes();
         attrs.privateFlags = (attrs.privateFlags & ~mask) | (flags & mask);
+        dispatchWindowAttributesChanged(attrs);
+    }
+
+    /**
+     * {@hide}
+     */
+    protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
         if (mCallback != null) {
             mCallback.onWindowAttributesChanged(attrs);
         }
@@ -818,9 +811,7 @@
         final WindowManager.LayoutParams attrs = getAttributes();
         attrs.dimAmount = amount;
         mHaveDimAmount = true;
-        if (mCallback != null) {
-            mCallback.onWindowAttributesChanged(attrs);
-        }
+        dispatchWindowAttributesChanged(attrs);
     }
 
     /**
@@ -835,9 +826,7 @@
      */
     public void setAttributes(WindowManager.LayoutParams a) {
         mWindowAttributes.copyFrom(a);
-        if (mCallback != null) {
-            mCallback.onWindowAttributesChanged(mWindowAttributes);
-        }
+        dispatchWindowAttributesChanged(mWindowAttributes);
     }
 
     /**
@@ -1269,9 +1258,7 @@
         if (!mHaveWindowFormat) {
             final WindowManager.LayoutParams attrs = getAttributes();
             attrs.format = format;
-            if (mCallback != null) {
-                mCallback.onWindowAttributesChanged(attrs);
-            }
+            dispatchWindowAttributesChanged(attrs);
         }
     }
 
@@ -1527,4 +1514,44 @@
      * until the called Activity's exiting transition completes.
      */
     public boolean getAllowExitTransitionOverlap() { return true; }
+
+    /**
+     * @return the color of the status bar.
+     */
+    public abstract int getStatusBarColor();
+
+    /**
+     * Sets the color of the status bar to {@param color}.
+     *
+     * For this to take effect,
+     * the window must be drawing the system bar backgrounds with
+     * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and
+     * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS} must not be set.
+     *
+     * If {@param color} is not opaque, consider setting
+     * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
+     * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
+     */
+    public abstract void setStatusBarColor(int color);
+
+    /**
+     * @return the color of the navigation bar.
+     */
+    public abstract int getNavigationBarColor();
+
+    /**
+     * Sets the color of the navigation bar to {@param color}.
+     *
+     * For this to take effect,
+     * the window must be drawing the system bar backgrounds with
+     * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} and
+     * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION} must not be set.
+     *
+     * If {@param color} is not opaque, consider setting
+     * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
+     * {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
+     */
+    public abstract void setNavigationBarColor(int color);
+
+
 }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 032a82f..031ad80 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -915,6 +915,14 @@
         public static final int FLAG_NEEDS_MENU_KEY = 0x40000000;
 
         /**
+         * Flag indicating that this Window is responsible for drawing the background for the
+         * system bars. If set, the system bars are drawn with a transparent background and the
+         * corresponding areas in this window are filled with the colors specified in
+         * {@link Window#getStatusBarColor()} and {@link Window#getNavigationBarColor()}.
+         */
+        public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000;
+
+        /**
          * Various behavioral options/flags.  Default is none.
          * 
          * @see #FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
@@ -941,6 +949,7 @@
          * @see #FLAG_SPLIT_TOUCH
          * @see #FLAG_HARDWARE_ACCELERATED
          * @see #FLAG_LOCAL_FOCUS_MODE
+         * @see #FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
          */
         @ViewDebug.ExportedProperty(flagMapping = {
             @ViewDebug.FlagToString(mask = FLAG_ALLOW_LOCK_WHILE_SCREEN_ON, equals = FLAG_ALLOW_LOCK_WHILE_SCREEN_ON,
@@ -998,7 +1007,9 @@
             @ViewDebug.FlagToString(mask = FLAG_TRANSLUCENT_STATUS, equals = FLAG_TRANSLUCENT_STATUS,
                     name = "FLAG_TRANSLUCENT_STATUS"),
             @ViewDebug.FlagToString(mask = FLAG_TRANSLUCENT_NAVIGATION, equals = FLAG_TRANSLUCENT_NAVIGATION,
-                    name = "FLAG_TRANSLUCENT_NAVIGATION")
+                    name = "FLAG_TRANSLUCENT_NAVIGATION"),
+            @ViewDebug.FlagToString(mask = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, equals = FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                    name = "FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS")
         })
         public int flags;
 
diff --git a/core/java/android/webkit/BrowserDownloadListener.java b/core/java/android/webkit/BrowserDownloadListener.java
deleted file mode 100644
index 724cc62..0000000
--- a/core/java/android/webkit/BrowserDownloadListener.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.webkit;
-
-/**
- * An abstract download listener that allows passing extra information as
- * part of onDownloadStart callback.
- * @hide
- */
-public abstract class BrowserDownloadListener implements DownloadListener {
-
-    /**
-     * Notify the host application that a file should be downloaded
-     * @param url The full url to the content that should be downloaded
-     * @param userAgent the user agent to be used for the download.
-     * @param contentDisposition Content-disposition http header, if
-     *                           present.
-     * @param mimetype The mimetype of the content reported by the server
-     * @param referer The referer associated with this url
-     * @param contentLength The file size reported by the server
-     */
-    public abstract void onDownloadStart(String url, String userAgent,
-            String contentDisposition, String mimetype, String referer,
-            long contentLength);
-
-
-    /**
-     * Notify the host application that a file should be downloaded
-     * @param url The full url to the content that should be downloaded
-     * @param userAgent the user agent to be used for the download.
-     * @param contentDisposition Content-disposition http header, if
-     *                           present.
-     * @param mimetype The mimetype of the content reported by the server
-     * @param contentLength The file size reported by the server
-     */
-    @Override
-    public void onDownloadStart(String url, String userAgent,
-            String contentDisposition, String mimetype, long contentLength) {
-
-        onDownloadStart(url, userAgent, contentDisposition, mimetype, null,
-                      contentLength);
-    }
-}
diff --git a/core/java/android/webkit/WebBackForwardListClient.java b/core/java/android/webkit/WebBackForwardListClient.java
deleted file mode 100644
index 7fe9281..0000000
--- a/core/java/android/webkit/WebBackForwardListClient.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.webkit;
-
-/**
- * Interface to receive notifications when items are added to the
- * {@link WebBackForwardList}.
- * {@hide}
- */
-public abstract class WebBackForwardListClient {
-
-    /**
-     * Notify the client that <var>item</var> has been added to the
-     * WebBackForwardList.
-     * @param item The newly created WebHistoryItem
-     */
-    public void onNewHistoryItem(WebHistoryItem item) { }
-
-    /**
-     * Notify the client that the <var>item</var> at <var>index</var> is now
-     * the current history item.
-     * @param item A WebHistoryItem
-     * @param index The new history index
-     */
-    public void onIndexChanged(WebHistoryItem item, int index) { }
-}
diff --git a/core/java/android/widget/RtlSpacingHelper.java b/core/java/android/widget/RtlSpacingHelper.java
new file mode 100644
index 0000000..f6b116f
--- /dev/null
+++ b/core/java/android/widget/RtlSpacingHelper.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+
+package android.widget;
+
+/**
+ * RtlSpacingHelper manages the relationship between left/right and start/end for views
+ * that need to maintain both absolute and relative settings for a form of spacing similar
+ * to view padding.
+ */
+class RtlSpacingHelper {
+    public static final int UNDEFINED = Integer.MIN_VALUE;
+
+    private int mLeft = 0;
+    private int mRight = 0;
+    private int mStart = UNDEFINED;
+    private int mEnd = UNDEFINED;
+    private int mExplicitLeft = 0;
+    private int mExplicitRight = 0;
+
+    private boolean mIsRtl = false;
+    private boolean mIsRelative = false;
+
+    public int getLeft() {
+        return mLeft;
+    }
+
+    public int getRight() {
+        return mRight;
+    }
+
+    public int getStart() {
+        return mIsRtl ? mRight : mLeft;
+    }
+
+    public int getEnd() {
+        return mIsRtl ? mLeft : mRight;
+    }
+
+    public void setRelative(int start, int end) {
+        mStart = start;
+        mEnd = end;
+        mIsRelative = true;
+        if (mIsRtl) {
+            if (end != UNDEFINED) mLeft = end;
+            if (start != UNDEFINED) mRight = start;
+        } else {
+            if (start != UNDEFINED) mLeft = start;
+            if (end != UNDEFINED) mRight = end;
+        }
+    }
+
+    public void setAbsolute(int left, int right) {
+        mIsRelative = false;
+        if (left != UNDEFINED) mLeft = mExplicitLeft = left;
+        if (right != UNDEFINED) mRight = mExplicitRight = right;
+    }
+
+    public void setDirection(boolean isRtl) {
+        if (isRtl == mIsRtl) {
+            return;
+        }
+        mIsRtl = isRtl;
+        if (mIsRelative) {
+            if (isRtl) {
+                mLeft = mEnd != UNDEFINED ? mEnd : mExplicitLeft;
+                mRight = mStart != UNDEFINED ? mStart : mExplicitRight;
+            } else {
+                mLeft = mStart != UNDEFINED ? mStart : mExplicitLeft;
+                mRight = mEnd != UNDEFINED ? mEnd : mExplicitRight;
+            }
+        } else {
+            mLeft = mExplicitLeft;
+            mRight = mExplicitRight;
+        }
+    }
+}
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 438e164..74a3eec 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -666,6 +666,8 @@
             case MotionEvent.ACTION_CANCEL: {
                 if (mTouchMode == TOUCH_MODE_DRAGGING) {
                     stopDrag(ev);
+                    // Allow super class to handle pressed state, etc.
+                    super.onTouchEvent(ev);
                     return true;
                 }
                 mTouchMode = TOUCH_MODE_IDLE;
@@ -801,7 +803,7 @@
     }
 
     @Override
-    protected void onDraw(Canvas canvas) {
+    public void draw(Canvas c) {
         final Rect tempRect = mTempRect;
         final Drawable trackDrawable = mTrackDrawable;
         final Drawable thumbDrawable = mThumbDrawable;
@@ -815,9 +817,6 @@
         trackDrawable.getPadding(tempRect);
 
         final int switchInnerLeft = switchLeft + tempRect.left;
-        final int switchInnerTop = switchTop + tempRect.top;
-        final int switchInnerRight = switchRight - tempRect.right;
-        final int switchInnerBottom = switchBottom - tempRect.bottom;
 
         // Relies on mTempRect, MUST be called first!
         final int thumbPos = getThumbOffset();
@@ -833,8 +832,26 @@
             background.setHotspotBounds(thumbLeft, switchTop, thumbRight, switchBottom);
         }
 
+        // Draw the background.
+        super.draw(c);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
 
+        final Rect tempRect = mTempRect;
+        final Drawable trackDrawable = mTrackDrawable;
+        final Drawable thumbDrawable = mThumbDrawable;
+        trackDrawable.getPadding(tempRect);
+
+        final int switchTop = mSwitchTop;
+        final int switchBottom = mSwitchBottom;
+        final int switchInnerLeft = mSwitchLeft + tempRect.left;
+        final int switchInnerTop = switchTop + tempRect.top;
+        final int switchInnerRight = mSwitchRight - tempRect.right;
+        final int switchInnerBottom = switchBottom - tempRect.bottom;
+
         if (mSplitTrack) {
             final Insets insets = thumbDrawable.getOpticalInsets();
             thumbDrawable.copyBounds(tempRect);
@@ -861,7 +878,8 @@
             }
             mTextPaint.drawableState = drawableState;
 
-            final int left = (thumbLeft + thumbRight) / 2 - switchText.getWidth() / 2;
+            final Rect thumbBounds = thumbDrawable.getBounds();
+            final int left = (thumbBounds.left + thumbBounds.right) / 2 - switchText.getWidth() / 2;
             final int top = (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2;
             canvas.translate(left, top);
             switchText.draw(canvas);
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 928e34e..f903346 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -88,11 +88,14 @@
 
     private int mTitleTextAppearance;
     private int mSubtitleTextAppearance;
+
     private int mTitleMarginStart;
     private int mTitleMarginEnd;
     private int mTitleMarginTop;
     private int mTitleMarginBottom;
 
+    private final RtlSpacingHelper mContentInsets = new RtlSpacingHelper();
+
     private int mGravity = Gravity.START | Gravity.CENTER_VERTICAL;
 
     private CharSequence mTitleText;
@@ -135,8 +138,8 @@
         mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);
         mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0);
         mGravity = a.getInteger(R.styleable.Toolbar_gravity, mGravity);
-        mTitleMarginStart = mTitleMarginEnd = Math.max(0, a.getDimensionPixelOffset(
-                R.styleable.Toolbar_titleMargins, -1));
+        mTitleMarginStart = mTitleMarginEnd = mTitleMarginTop = mTitleMarginBottom =
+                a.getDimensionPixelOffset(R.styleable.Toolbar_titleMargins, 0);
 
         final int marginStart = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginStart, -1);
         if (marginStart >= 0) {
@@ -159,6 +162,24 @@
             mTitleMarginBottom = marginBottom;
         }
 
+        final int contentInsetStart =
+                a.getDimensionPixelOffset(R.styleable.Toolbar_contentInsetStart,
+                        RtlSpacingHelper.UNDEFINED);
+        final int contentInsetEnd =
+                a.getDimensionPixelOffset(R.styleable.Toolbar_contentInsetEnd,
+                        RtlSpacingHelper.UNDEFINED);
+        final int contentInsetLeft =
+                a.getDimensionPixelSize(R.styleable.Toolbar_contentInsetLeft, 0);
+        final int contentInsetRight =
+                a.getDimensionPixelSize(R.styleable.Toolbar_contentInsetRight, 0);
+
+        mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);
+
+        if (contentInsetStart != RtlSpacingHelper.UNDEFINED ||
+                contentInsetEnd != RtlSpacingHelper.UNDEFINED) {
+            mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
+        }
+
         final CharSequence title = a.getText(R.styleable.Toolbar_title);
         if (!TextUtils.isEmpty(title)) {
             setTitle(title);
@@ -171,6 +192,12 @@
         a.recycle();
     }
 
+    @Override
+    public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+        mContentInsets.setDirection(layoutDirection == LAYOUT_DIRECTION_RTL);
+    }
+
     /**
      * Set a logo drawable from a resource id.
      *
@@ -489,6 +516,122 @@
         mOnMenuItemClickListener = listener;
     }
 
+    /**
+     * Set the content insets for this toolbar relative to layout direction.
+     *
+     * <p>The content inset affects the valid area for Toolbar content other than
+     * the navigation button and menu. Insets define the minimum margin for these components
+     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
+     *
+     * @param contentInsetStart Content inset for the toolbar starting edge
+     * @param contentInsetEnd Content inset for the toolbar ending edge
+     *
+     * @see #setContentInsetsAbsolute(int, int)
+     * @see #getContentInsetStart()
+     * @see #getContentInsetEnd()
+     * @see #getContentInsetLeft()
+     * @see #getContentInsetRight()
+     */
+    public void setContentInsetsRelative(int contentInsetStart, int contentInsetEnd) {
+        mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
+    }
+
+    /**
+     * Get the starting content inset for this toolbar.
+     *
+     * <p>The content inset affects the valid area for Toolbar content other than
+     * the navigation button and menu. Insets define the minimum margin for these components
+     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
+     *
+     * @return The starting content inset for this toolbar
+     *
+     * @see #setContentInsetsRelative(int, int)
+     * @see #setContentInsetsAbsolute(int, int)
+     * @see #getContentInsetEnd()
+     * @see #getContentInsetLeft()
+     * @see #getContentInsetRight()
+     */
+    public int getContentInsetStart() {
+        return mContentInsets.getStart();
+    }
+
+    /**
+     * Get the ending content inset for this toolbar.
+     *
+     * <p>The content inset affects the valid area for Toolbar content other than
+     * the navigation button and menu. Insets define the minimum margin for these components
+     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
+     *
+     * @return The ending content inset for this toolbar
+     *
+     * @see #setContentInsetsRelative(int, int)
+     * @see #setContentInsetsAbsolute(int, int)
+     * @see #getContentInsetStart()
+     * @see #getContentInsetLeft()
+     * @see #getContentInsetRight()
+     */
+    public int getContentInsetEnd() {
+        return mContentInsets.getEnd();
+    }
+
+    /**
+     * Set the content insets for this toolbar.
+     *
+     * <p>The content inset affects the valid area for Toolbar content other than
+     * the navigation button and menu. Insets define the minimum margin for these components
+     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
+     *
+     * @param contentInsetLeft Content inset for the toolbar's left edge
+     * @param contentInsetRight Content inset for the toolbar's right edge
+     *
+     * @see #setContentInsetsAbsolute(int, int)
+     * @see #getContentInsetStart()
+     * @see #getContentInsetEnd()
+     * @see #getContentInsetLeft()
+     * @see #getContentInsetRight()
+     */
+    public void setContentInsetsAbsolute(int contentInsetLeft, int contentInsetRight) {
+        mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);
+    }
+
+    /**
+     * Get the left content inset for this toolbar.
+     *
+     * <p>The content inset affects the valid area for Toolbar content other than
+     * the navigation button and menu. Insets define the minimum margin for these components
+     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
+     *
+     * @return The left content inset for this toolbar
+     *
+     * @see #setContentInsetsRelative(int, int)
+     * @see #setContentInsetsAbsolute(int, int)
+     * @see #getContentInsetStart()
+     * @see #getContentInsetEnd()
+     * @see #getContentInsetRight()
+     */
+    public int getContentInsetLeft() {
+        return mContentInsets.getLeft();
+    }
+
+    /**
+     * Get the right content inset for this toolbar.
+     *
+     * <p>The content inset affects the valid area for Toolbar content other than
+     * the navigation button and menu. Insets define the minimum margin for these components
+     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
+     *
+     * @return The right content inset for this toolbar
+     *
+     * @see #setContentInsetsRelative(int, int)
+     * @see #setContentInsetsAbsolute(int, int)
+     * @see #getContentInsetStart()
+     * @see #getContentInsetEnd()
+     * @see #getContentInsetLeft()
+     */
+    public int getContentInsetRight() {
+        return mContentInsets.getRight();
+    }
+
     private void ensureNavButtonView() {
         if (mNavButtonView == null) {
             mNavButtonView = new ImageButton(getContext(), null, R.attr.borderlessButtonStyle);
@@ -522,22 +665,28 @@
 
         // System views measure first.
 
+        int navWidth = 0;
         if (shouldLayout(mNavButtonView)) {
             measureChildWithMargins(mNavButtonView, widthMeasureSpec, width, heightMeasureSpec, 0);
-            width += mNavButtonView.getMeasuredWidth() + getHorizontalMargins(mNavButtonView);
+            navWidth = mNavButtonView.getMeasuredWidth() + getHorizontalMargins(mNavButtonView);
             height = Math.max(height, mNavButtonView.getMeasuredHeight() +
                     getVerticalMargins(mNavButtonView));
             childState = combineMeasuredStates(childState, mNavButtonView.getMeasuredState());
         }
 
+        width += Math.max(getContentInsetStart(), navWidth);
+
+        int menuWidth = 0;
         if (shouldLayout(mMenuView)) {
             measureChildWithMargins(mMenuView, widthMeasureSpec, width, heightMeasureSpec, 0);
-            width += mMenuView.getMeasuredWidth() + getHorizontalMargins(mMenuView);
+            menuWidth = mMenuView.getMeasuredWidth() + getHorizontalMargins(mMenuView);
             height = Math.max(height, mMenuView.getMeasuredHeight() +
                     getVerticalMargins(mMenuView));
             childState = combineMeasuredStates(childState, mMenuView.getMeasuredState());
         }
 
+        width += Math.max(getContentInsetEnd(), menuWidth);
+
         if (shouldLayout(mLogoView)) {
             measureChildWithMargins(mLogoView, widthMeasureSpec, width, heightMeasureSpec, 0);
             width += mLogoView.getMeasuredWidth() + getHorizontalMargins(mLogoView);
@@ -627,6 +776,9 @@
             }
         }
 
+        left = Math.max(left, getContentInsetLeft());
+        right = Math.min(right, width - paddingRight - getContentInsetRight());
+
         if (shouldLayout(mLogoView)) {
             if (isRtl) {
                 right = layoutChildRight(mLogoView, right);
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index f23c64f..2b62552 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -30,6 +30,7 @@
 import android.media.Metadata;
 import android.media.SubtitleController;
 import android.media.SubtitleTrack.RenderingWidget;
+import android.media.TtmlRenderer;
 import android.media.WebVttRenderer;
 import android.net.Uri;
 import android.os.Looper;
@@ -314,6 +315,7 @@
             final SubtitleController controller = new SubtitleController(
                     context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer);
             controller.registerRenderer(new WebVttRenderer(context));
+            controller.registerRenderer(new TtmlRenderer(context));
             mMediaPlayer.setSubtitleAnchor(controller, this);
 
             if (mAudioSession != 0) {
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index cd75010..8e6fa58 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.app;
 
 import android.app.AppOpsManager;
+import android.os.Bundle;
 import com.android.internal.app.IAppOpsCallback;
 
 interface IAppOpsService {
@@ -38,4 +39,10 @@
     void resetAllModes();
     int checkAudioOperation(int code, int stream, int uid, String packageName);
     void setAudioRestriction(int code, int stream, int uid, int mode, in String[] exceptionPackages);
+
+    void setDeviceOwner(String packageName);
+    void setProfileOwner(String packageName, int userHandle);
+    void setUserRestrictions(in Bundle restrictions, int userHandle);
+    void removeUser(int userHandle);
+
 }
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 04547495..0769b08 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -46,14 +46,15 @@
 
     void noteStartWakelock(int uid, int pid, String name, String historyName,
             int type, boolean unimportantForLogging);
-    void noteStopWakelock(int uid, int pid, String name, int type);
+    void noteStopWakelock(int uid, int pid, String name, String historyName, int type);
 
     void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, String historyName,
             int type, boolean unimportantForLogging);
-    void noteChangeWakelockFromSource(in WorkSource ws, int pid, String name, int type,
-            in WorkSource newWs, int newPid, String newName,
+    void noteChangeWakelockFromSource(in WorkSource ws, int pid, String name, String histyoryName,
+            int type, in WorkSource newWs, int newPid, String newName,
             String newHistoryName, int newType, boolean newUnimportantForLogging);
-    void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, int type);
+    void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, String historyName,
+            int type);
 
     void noteVibratorOn(int uid, long durationMillis);
     void noteVibratorOff(int uid);
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 66548f0..79a8f44 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -268,7 +268,7 @@
             if (getNavigationMode() == NAVIGATION_MODE_TABS) {
                 tabScroller.setVisibility(View.VISIBLE);
                 if (mOverlayLayout != null) {
-                    mOverlayLayout.requestFitSystemWindows();
+                    mOverlayLayout.requestApplyInsets();
                 }
             } else {
                 tabScroller.setVisibility(View.GONE);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 7bd5b12..8428f66 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -48,7 +48,6 @@
 import android.util.Printer;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.view.Display;
@@ -89,7 +88,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 105 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 106 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -236,6 +235,8 @@
 
     int mWakeLockNesting;
     boolean mWakeLockImportant;
+    boolean mRecordAllWakeLocks;
+    boolean mNoAutoReset;
 
     int mScreenState = Display.STATE_UNKNOWN;
     StopwatchTimer mScreenOnTimer;
@@ -246,6 +247,9 @@
     boolean mInteractive;
     StopwatchTimer mInteractiveTimer;
 
+    boolean mLowPowerModeEnabled;
+    StopwatchTimer mLowPowerModeEnabledTimer;
+
     boolean mPhoneOn;
     StopwatchTimer mPhoneOnTimer;
 
@@ -2311,6 +2315,18 @@
         }
     }
 
+    public void setRecordAllWakeLocksLocked(boolean enabled) {
+        mRecordAllWakeLocks = enabled;
+        if (!enabled) {
+            // Clear out any existing state.
+            mActiveEvents.removeEvents(HistoryItem.EVENT_WAKE_LOCK);
+        }
+    }
+
+    public void setNoAutoReset(boolean enabled) {
+        mNoAutoReset = enabled;
+    }
+
     private String mInitialAcquireWakeName;
     private int mInitialAcquireWakeUid = -1;
 
@@ -2321,27 +2337,34 @@
             // Only care about partial wake locks, since full wake locks
             // will be canceled when the user puts the screen to sleep.
             aggregateLastWakeupUptimeLocked(uptime);
+            historyName = historyName == null || mRecordAllWakeLocks ? name : historyName;
             if (mWakeLockNesting == 0) {
                 mHistoryCur.states |= HistoryItem.STATE_WAKE_LOCK_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
                         + Integer.toHexString(mHistoryCur.states));
                 mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
-                mHistoryCur.wakelockTag.string = mInitialAcquireWakeName
-                        = historyName != null ? historyName : name;
+                mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
                 mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
                 mWakeLockImportant = !unimportantForLogging;
                 addHistoryRecordLocked(elapsedRealtime, uptime);
-            } else if (!mWakeLockImportant && !unimportantForLogging) {
+            } else if (!mRecordAllWakeLocks && !mWakeLockImportant && !unimportantForLogging) {
                 if (mHistoryLastWritten.wakelockTag != null) {
                     // We'll try to update the last tag.
                     mHistoryLastWritten.wakelockTag = null;
                     mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
-                    mHistoryCur.wakelockTag.string = mInitialAcquireWakeName
-                            = historyName != null ? historyName : name;
+                    mHistoryCur.wakelockTag.string = mInitialAcquireWakeName = historyName;
                     mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
                     addHistoryRecordLocked(elapsedRealtime, uptime);
                 }
                 mWakeLockImportant = true;
+            } else if (mRecordAllWakeLocks) {
+                if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_START, historyName,
+                        uid, 0)) {
+                    mWakeLockNesting++;
+                    return;
+                }
+                addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_WAKE_LOCK_START,
+                        historyName, uid);
             }
             mWakeLockNesting++;
         }
@@ -2354,24 +2377,33 @@
         }
     }
 
-    public void noteStopWakeLocked(int uid, int pid, String name, int type, long elapsedRealtime,
-            long uptime) {
+    public void noteStopWakeLocked(int uid, int pid, String name, String historyName, int type,
+            long elapsedRealtime, long uptime) {
         uid = mapUid(uid);
         if (type == WAKE_TYPE_PARTIAL) {
             mWakeLockNesting--;
+            historyName = historyName == null || mRecordAllWakeLocks ? name : historyName;
             if (mWakeLockNesting == 0) {
                 mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG;
                 if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: "
                         + Integer.toHexString(mHistoryCur.states));
-                if ((name != null && !name.equals(mInitialAcquireWakeName))
+                if (mRecordAllWakeLocks
+                        || (historyName != null && !historyName.equals(mInitialAcquireWakeName))
                         || uid != mInitialAcquireWakeUid) {
                     mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
-                    mHistoryCur.wakelockTag.string = name;
+                    mHistoryCur.wakelockTag.string = historyName;
                     mHistoryCur.wakelockTag.uid = uid;
                 }
                 mInitialAcquireWakeName = null;
                 mInitialAcquireWakeUid = -1;
                 addHistoryRecordLocked(elapsedRealtime, uptime);
+            } else if (mRecordAllWakeLocks) {
+                if (mActiveEvents.updateState(HistoryItem.EVENT_WAKE_LOCK_FINISH, historyName,
+                        uid, 0)) {
+                    return;
+                }
+                addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_WAKE_LOCK_FINISH,
+                        historyName, uid);
             }
         }
         if (uid >= 0) {
@@ -2391,8 +2423,8 @@
         }
     }
 
-    public void noteChangeWakelockFromSourceLocked(WorkSource ws, int pid, String name, int type,
-            WorkSource newWs, int newPid, String newName,
+    public void noteChangeWakelockFromSourceLocked(WorkSource ws, int pid, String name,
+            String historyName, int type, WorkSource newWs, int newPid, String newName,
             String newHistoryName, int newType, boolean newUnimportantForLogging) {
         final long elapsedRealtime = SystemClock.elapsedRealtime();
         final long uptime = SystemClock.uptimeMillis();
@@ -2406,16 +2438,17 @@
         }
         final int NO = ws.size();
         for (int i=0; i<NO; i++) {
-            noteStopWakeLocked(ws.get(i), pid, name, type, elapsedRealtime, uptime);
+            noteStopWakeLocked(ws.get(i), pid, name, historyName, type, elapsedRealtime, uptime);
         }
     }
 
-    public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) {
+    public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name,
+            String historyName, int type) {
         final long elapsedRealtime = SystemClock.elapsedRealtime();
         final long uptime = SystemClock.uptimeMillis();
         final int N = ws.size();
         for (int i=0; i<N; i++) {
-            noteStopWakeLocked(ws.get(i), pid, name, type, elapsedRealtime, uptime);
+            noteStopWakeLocked(ws.get(i), pid, name, historyName, type, elapsedRealtime, uptime);
         }
     }
 
@@ -2684,7 +2717,7 @@
                     mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(elapsedRealtime);
                 }
 
-                noteStopWakeLocked(-1, -1, "screen", WAKE_TYPE_PARTIAL,
+                noteStopWakeLocked(-1, -1, "screen", "screen", WAKE_TYPE_PARTIAL,
                         elapsedRealtime, uptime);
 
                 updateTimeBasesLocked(mOnBatteryTimeBase.isRunning(), true,
@@ -2780,6 +2813,26 @@
         }
     }
 
+    public void noteLowPowerMode(boolean enabled) {
+        if (mLowPowerModeEnabled != enabled) {
+            final long elapsedRealtime = SystemClock.elapsedRealtime();
+            final long uptime = SystemClock.uptimeMillis();
+            mLowPowerModeEnabled = enabled;
+            if (enabled) {
+                mHistoryCur.states2 |= HistoryItem.STATE2_LOW_POWER_FLAG;
+                if (DEBUG_HISTORY) Slog.v(TAG, "Low power mode enabled to: "
+                        + Integer.toHexString(mHistoryCur.states2));
+                mLowPowerModeEnabledTimer.startRunningLocked(elapsedRealtime);
+            } else {
+                mHistoryCur.states2 &= ~HistoryItem.STATE2_LOW_POWER_FLAG;
+                if (DEBUG_HISTORY) Slog.v(TAG, "Low power mode disabled to: "
+                        + Integer.toHexString(mHistoryCur.states2));
+                mLowPowerModeEnabledTimer.stopRunningLocked(elapsedRealtime);
+            }
+            addHistoryRecordLocked(elapsedRealtime, uptime);
+        }
+    }
+
     public void notePhoneOnLocked() {
         if (!mPhoneOn) {
             final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -3443,6 +3496,14 @@
         return mInteractiveTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
 
+    @Override public long getLowPowerModeEnabledTime(long elapsedRealtimeUs, int which) {
+        return mLowPowerModeEnabledTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
+    }
+
+    @Override public int getLowPowerModeEnabledCount(int which) {
+        return mLowPowerModeEnabledTimer.getCountLocked(which);
+    }
+
     @Override public long getPhoneOnTime(long elapsedRealtimeUs, int which) {
         return mPhoneOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
     }
@@ -5489,7 +5550,8 @@
         for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             mScreenBrightnessTimer[i] = new StopwatchTimer(null, -100-i, null, mOnBatteryTimeBase);
         }
-        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase);
+        mLowPowerModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase);
+        mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i, null,
                     mOnBatteryTimeBase);
@@ -5508,18 +5570,18 @@
         mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase);
         mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase);
         mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase);
-        mWifiOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase);
-        mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase);
+        mWifiOnTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase);
+        mGlobalWifiRunningTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
             mWifiStateTimer[i] = new StopwatchTimer(null, -600-i, null, mOnBatteryTimeBase);
         }
-        mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase);
+        mBluetoothOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase);
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i, null, mOnBatteryTimeBase);
         }
-        mAudioOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase);
-        mVideoOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
-        mInteractiveTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
+        mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
+        mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
+        mInteractiveTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase);
         mOnBattery = mOnBatteryInternal = false;
         long uptime = SystemClock.uptimeMillis() * 1000;
         long realtime = SystemClock.elapsedRealtime() * 1000;
@@ -5765,6 +5827,7 @@
             mScreenBrightnessTimer[i].reset(false);
         }
         mInteractiveTimer.reset(false);
+        mLowPowerModeEnabledTimer.reset(false);
         mPhoneOnTimer.reset(false);
         mAudioOnTimer.reset(false);
         mVideoOnTimer.reset(false);
@@ -5885,9 +5948,9 @@
             // we have gone through a significant charge (from a very low
             // level to a now very high level).
             boolean reset = false;
-            if (oldStatus == BatteryManager.BATTERY_STATUS_FULL
+            if (!mNoAutoReset && (oldStatus == BatteryManager.BATTERY_STATUS_FULL
                     || level >= 90
-                    || (mDischargeCurrentLevel < 20 && level >= 80)) {
+                    || (mDischargeCurrentLevel < 20 && level >= 80))) {
                 doWrite = true;
                 resetAllStatsLocked();
                 mDischargeStartLevel = level;
@@ -6915,6 +6978,7 @@
         mInteractive = false;
         mInteractiveTimer.readSummaryFromParcelLocked(in);
         mPhoneOn = false;
+        mLowPowerModeEnabledTimer.readSummaryFromParcelLocked(in);
         mPhoneOnTimer.readSummaryFromParcelLocked(in);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             mPhoneSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
@@ -7169,6 +7233,7 @@
             mScreenBrightnessTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         }
         mInteractiveTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
+        mLowPowerModeEnabledTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             mPhoneSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
@@ -7431,7 +7496,8 @@
                     in);
         }
         mPhoneOn = false;
-        mPhoneOnTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+        mLowPowerModeEnabledTimer = new StopwatchTimer(null, -2, null, mOnBatteryTimeBase, in);
+        mPhoneOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase, in);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             mPhoneSignalStrengthsTimer[i] = new StopwatchTimer(null, -200-i,
                     null, mOnBatteryTimeBase, in);
@@ -7453,25 +7519,25 @@
         mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mWifiOn = false;
-        mWifiOnTimer = new StopwatchTimer(null, -3, null, mOnBatteryTimeBase, in);
+        mWifiOnTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase, in);
         mGlobalWifiRunning = false;
-        mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase, in);
+        mGlobalWifiRunningTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase, in);
         for (int i=0; i<NUM_WIFI_STATES; i++) {
             mWifiStateTimer[i] = new StopwatchTimer(null, -600-i,
                     null, mOnBatteryTimeBase, in);
         }
         mBluetoothOn = false;
-        mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mOnBatteryTimeBase, in);
+        mBluetoothOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase, in);
         for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
             mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i,
                     null, mOnBatteryTimeBase, in);
         }
         mAudioOn = false;
-        mAudioOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase);
+        mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
         mVideoOn = false;
-        mVideoOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
+        mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
         mInteractive = false;
-        mInteractiveTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase, in);
+        mInteractiveTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase, in);
         mDischargeUnplugLevel = in.readInt();
         mDischargePlugLevel = in.readInt();
         mDischargeCurrentLevel = in.readInt();
@@ -7570,6 +7636,7 @@
             mScreenBrightnessTimer[i].writeToParcel(out, uSecRealtime);
         }
         mInteractiveTimer.writeToParcel(out, uSecRealtime);
+        mLowPowerModeEnabledTimer.writeToParcel(out, uSecRealtime);
         mPhoneOnTimer.writeToParcel(out, uSecRealtime);
         for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
             mPhoneSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
@@ -7688,6 +7755,8 @@
             }
             pr.println("*** Interactive timer:");
             mInteractiveTimer.logState(pr, "  ");
+            pr.println("*** Low power mode timer:");
+            mLowPowerModeEnabledTimer.logState(pr, "  ");
             pr.println("*** Phone timer:");
             mPhoneOnTimer.logState(pr, "  ");
             for (int i=0; i<SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
index aec2b7e..1feb943 100644
--- a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
+++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
@@ -34,11 +34,11 @@
      * Used to cache the float[] LUT for use across multiple native
      * interpolator creation
      */
-    public FallbackLUTInterpolator(TimeInterpolator interpolator, int duration) {
+    public FallbackLUTInterpolator(TimeInterpolator interpolator, long duration) {
         mLut = createLUT(interpolator, duration);
     }
 
-    private static float[] createLUT(TimeInterpolator interpolator, int duration) {
+    private static float[] createLUT(TimeInterpolator interpolator, long duration) {
         long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos();
         int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
         int numAnimFrames = (int) Math.ceil(duration / animIntervalMs);
@@ -59,7 +59,7 @@
     /**
      * Used to create a one-shot float[] LUT & native interpolator
      */
-    public static long createNativeInterpolator(TimeInterpolator interpolator, int duration) {
+    public static long createNativeInterpolator(TimeInterpolator interpolator, long duration) {
         float[] lut = createLUT(interpolator, duration);
         return NativeInterpolatorFactoryHelper.createLutInterpolator(lut);
     }
diff --git a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
index 772dc5f..841a02a 100644
--- a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java
@@ -238,6 +238,10 @@
         Drawable pointDrawable = pointId != 0 ? context.getDrawable(pointId) : null;
         mGlowRadius = a.getDimension(R.styleable.GlowPadView_glowRadius, 0.0f);
 
+        mPointCloud = new PointCloud(pointDrawable);
+        mPointCloud.makePointCloud(mInnerRadius, mOuterRadius);
+        mPointCloud.glowManager.setRadius(mGlowRadius);
+
         TypedValue outValue = new TypedValue();
 
         // Read array of target drawables
@@ -273,10 +277,6 @@
         setVibrateEnabled(mVibrationDuration > 0);
 
         assignDefaultsIfNeeded();
-
-        mPointCloud = new PointCloud(pointDrawable);
-        mPointCloud.makePointCloud(mInnerRadius, mOuterRadius);
-        mPointCloud.glowManager.setRadius(mGlowRadius);
     }
 
     private int getResourceId(TypedArray a, int id) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 726b2f7..0ad2ab2 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -5,6 +5,7 @@
 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-non-virtual-dtor
 LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
 LOCAL_CPPFLAGS += -Wno-conversion-null
 
@@ -125,6 +126,7 @@
 	android/graphics/Xfermode.cpp \
 	android/graphics/YuvToJpegEncoder.cpp \
 	android/graphics/pdf/PdfDocument.cpp \
+	android/graphics/pdf/PdfRenderer.cpp \
 	android_media_AudioRecord.cpp \
 	android_media_AudioSystem.cpp \
 	android_media_AudioTrack.cpp \
@@ -169,6 +171,9 @@
 	$(call include-path-for, libhardware_legacy)/hardware_legacy \
 	$(TOP)/frameworks/av/include \
 	$(TOP)/system/media/camera/include \
+	external/pdfrenderer/core/include/fpdfapi \
+	external/pdfrenderer/core/include/fpdfdoc \
+	external/pdfrenderer/fpdfsdk/include \
 	external/skia/src/core \
 	external/skia/src/effects \
 	external/skia/src/images \
@@ -222,6 +227,7 @@
 	libharfbuzz_ng \
 	libz \
 	libaudioutils \
+	libpdfrenderer \
 
 ifeq ($(USE_OPENGL_RENDERER),true)
 	LOCAL_SHARED_LIBRARIES += libhwui
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f41af04..a4dc824 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -120,6 +120,7 @@
 extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
 extern int register_android_graphics_Xfermode(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
+extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
 extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
 extern int register_android_view_RenderNode(JNIEnv* env);
 extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
@@ -1258,6 +1259,7 @@
     REG_JNI(register_android_graphics_Xfermode),
     REG_JNI(register_android_graphics_YuvImage),
     REG_JNI(register_android_graphics_pdf_PdfDocument),
+    REG_JNI(register_android_graphics_pdf_PdfRenderer),
 
     REG_JNI(register_android_database_CursorWindow),
     REG_JNI(register_android_database_SQLiteConnection),
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index 23af860..cbd20e9 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -50,10 +50,17 @@
         SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
         return obj->isIdentity() ? JNI_TRUE : JNI_FALSE;
     }
+
+    static jboolean isAffine(JNIEnv* env, jobject clazz, jlong objHandle) {
+        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+        return obj->asAffine(NULL) ? JNI_TRUE : JNI_FALSE;
+    }
+
     static jboolean rectStaysRect(JNIEnv* env, jobject clazz, jlong objHandle) {
         SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
         return obj->rectStaysRect() ? JNI_TRUE : JNI_FALSE;
     }
+
     static void reset(JNIEnv* env, jobject clazz, jlong objHandle) {
         SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
         obj->reset();
@@ -302,6 +309,7 @@
     {"finalizer", "(J)V", (void*) SkMatrixGlue::finalizer},
     {"native_create","(J)J", (void*) SkMatrixGlue::create},
     {"native_isIdentity","(J)Z", (void*) SkMatrixGlue::isIdentity},
+    {"native_isAffine","(J)Z", (void*) SkMatrixGlue::isAffine},
     {"native_rectStaysRect","(J)Z", (void*) SkMatrixGlue::rectStaysRect},
     {"native_reset","(J)V", (void*) SkMatrixGlue::reset},
     {"native_set","(JJ)V", (void*) SkMatrixGlue::set},
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index bf58918..9279758 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -367,7 +367,6 @@
         bool forceLTR = false;
         bool forceRTL = false;
 
-        ALOGD("computeValues dirFlags=%d", dirFlags);
         switch (dirFlags & kBidi_Mask) {
             case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
             case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
new file mode 100644
index 0000000..15de24a
--- /dev/null
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -0,0 +1,279 @@
+/*
+ * 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.
+ */
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "GraphicsJNI.h"
+#include "SkBitmap.h"
+#include "SkMatrix.h"
+#include "fpdfview.h"
+#include "fsdk_rendercontext.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <vector>
+#include <utils/Log.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+
+static const int RENDER_MODE_FOR_DISPLAY = 1;
+static const int RENDER_MODE_FOR_PRINT = 2;
+
+static struct {
+    jfieldID x;
+    jfieldID y;
+} gPointClassInfo;
+
+static Mutex sLock;
+
+static int sUnmatchedInitRequestCount = 0;
+
+static void initializeLibraryIfNeeded() {
+    Mutex::Autolock _l(sLock);
+    if (sUnmatchedInitRequestCount == 0) {
+        FPDF_InitLibrary(NULL);
+    }
+    sUnmatchedInitRequestCount++;
+}
+
+static void destroyLibraryIfNeeded() {
+    Mutex::Autolock _l(sLock);
+    sUnmatchedInitRequestCount--;
+    if (sUnmatchedInitRequestCount == 0) {
+       FPDF_DestroyLibrary();
+    }
+}
+
+static int getBlock(void* param, unsigned long position, unsigned char* outBuffer,
+        unsigned long size) {
+    const int fd = reinterpret_cast<intptr_t>(param);
+    const int readCount = pread(fd, outBuffer, size, position);
+    if (readCount < 0) {
+        ALOGE("Cannot read from file descriptor. Error:%d", errno);
+        return 0;
+    }
+    return 1;
+}
+
+static jlong nativeCreate(JNIEnv* env, jclass thiz, jint fd, jlong size) {
+    initializeLibraryIfNeeded();
+
+    FPDF_FILEACCESS loader;
+    loader.m_FileLen = size;
+    loader.m_Param = reinterpret_cast<void*>(intptr_t(fd));
+    loader.m_GetBlock = &getBlock;
+
+    FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL);
+
+    if (!document) {
+        const long error = FPDF_GetLastError();
+        jniThrowException(env, "java/io/IOException",
+                "cannot create document. Error:" + error);
+        destroyLibraryIfNeeded();
+        return -1;
+    }
+
+    return reinterpret_cast<jlong>(document);
+}
+
+static jlong nativeOpenPageAndGetSize(JNIEnv* env, jclass thiz, jlong documentPtr,
+        jint pageIndex, jobject outSize) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+    FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+
+    if (!page) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "cannot load page");
+        return -1;
+    }
+
+    double width = 0;
+    double height = 0;
+
+    const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
+
+    if (!result) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                    "cannot get page size");
+        return -1;
+    }
+
+    env->SetIntField(outSize, gPointClassInfo.x, width);
+    env->SetIntField(outSize, gPointClassInfo.y, height);
+
+    return reinterpret_cast<jlong>(page);
+}
+
+static void nativeClosePage(JNIEnv* env, jclass thiz, jlong pagePtr) {
+    FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
+    FPDF_ClosePage(page);
+}
+
+static void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+    FPDF_CloseDocument(document);
+    destroyLibraryIfNeeded();
+}
+
+static jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+    return FPDF_GetPageCount(document);
+}
+
+static jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+    return FPDF_VIEWERREF_GetPrintScaling(document);
+}
+
+static void DropContext(void* data) {
+    delete (CRenderContext*) data;
+}
+
+static void renderPageBitmap(FPDF_BITMAP bitmap, FPDF_PAGE page, int destLeft, int destTop,
+        int destRight, int destBottom, SkMatrix* transform, int flags) {
+    // Note: this code ignores the currently unused RENDER_NO_NATIVETEXT,
+    // FPDF_RENDER_LIMITEDIMAGECACHE, FPDF_RENDER_FORCEHALFTONE, FPDF_GRAYSCALE,
+    // and FPDF_ANNOT flags. To add support for that refer to FPDF_RenderPage_Retail
+    // in fpdfview.cpp
+
+    CRenderContext* pContext = FX_NEW CRenderContext;
+
+    CPDF_Page* pPage = (CPDF_Page*) page;
+    pPage->SetPrivateData((void*) 1, pContext, DropContext);
+
+    CFX_FxgeDevice* fxgeDevice = FX_NEW CFX_FxgeDevice;
+    pContext->m_pDevice = fxgeDevice;
+
+    // Reverse the bytes (last argument TRUE) since the Android
+    // format is ARGB while the renderer uses BGRA internally.
+    fxgeDevice->Attach((CFX_DIBitmap*) bitmap, 0, TRUE);
+
+    CPDF_RenderOptions* renderOptions = pContext->m_pOptions;
+
+    if (!renderOptions) {
+        renderOptions = FX_NEW CPDF_RenderOptions;
+        pContext->m_pOptions = renderOptions;
+    }
+
+    if (flags & FPDF_LCD_TEXT) {
+        renderOptions->m_Flags |= RENDER_CLEARTYPE;
+    } else {
+        renderOptions->m_Flags &= ~RENDER_CLEARTYPE;
+    }
+
+    const CPDF_OCContext::UsageType usage = (flags & FPDF_PRINTING)
+            ? CPDF_OCContext::Print : CPDF_OCContext::View;
+
+    renderOptions->m_AddFlags = flags >> 8;
+    renderOptions->m_pOCContext = new CPDF_OCContext(pPage->m_pDocument, usage);
+
+    fxgeDevice->SaveState();
+
+    FX_RECT clip;
+    clip.left = destLeft;
+    clip.right = destRight;
+    clip.top = destTop;
+    clip.bottom = destBottom;
+    fxgeDevice->SetClip_Rect(&clip);
+
+    CPDF_RenderContext* pageContext = FX_NEW CPDF_RenderContext;
+    pContext->m_pContext = pageContext;
+    pageContext->Create(pPage);
+
+    CFX_AffineMatrix matrix;
+    if (!transform) {
+        pPage->GetDisplayMatrix(matrix, destLeft, destTop, destRight - destLeft,
+                destBottom - destTop, 0);
+    } else {
+        // PDF's coordinate system origin is left-bottom while
+        // in graphics it is the top-left, so remap the origin.
+        matrix.Set(1, 0, 0, -1, 0, pPage->GetPageHeight());
+        matrix.Scale(transform->getScaleX(), transform->getScaleY());
+        matrix.Rotate(transform->getSkewX(), transform->getSkewY());
+        matrix.Translate(transform->getTranslateX(), transform->getTranslateY());
+    }
+    pageContext->AppendObjectList(pPage, &matrix);
+
+    pContext->m_pRenderer = FX_NEW CPDF_ProgressiveRenderer;
+    pContext->m_pRenderer->Start(pageContext, fxgeDevice, renderOptions, NULL);
+
+    fxgeDevice->RestoreState();
+
+    pPage->RemovePrivateData((void*) 1);
+
+    delete pContext;
+}
+
+static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong pagePtr,
+        jlong bitmapPtr, jint destLeft, jint destTop, jint destRight, jint destBottom,
+        jlong matrixPtr, jint renderMode) {
+
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+    FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
+    SkBitmap* skBitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
+    SkMatrix* skMatrix = reinterpret_cast<SkMatrix*>(matrixPtr);
+
+    skBitmap->lockPixels();
+
+    const int stride = skBitmap->width() * 4;
+
+    FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap->width(), skBitmap->height(),
+            FPDFBitmap_BGRA, skBitmap->getPixels(), stride);
+
+    if (!bitmap) {
+        ALOGE("Erorr creating bitmap");
+        return;
+    }
+
+    int renderFlags = 0;
+    if (renderMode == RENDER_MODE_FOR_DISPLAY) {
+        renderFlags |= FPDF_LCD_TEXT;
+    } else if (renderMode == RENDER_MODE_FOR_PRINT) {
+        renderFlags |= FPDF_PRINTING;
+    }
+
+    renderPageBitmap(bitmap, page, destLeft, destTop, destRight,
+            destBottom, skMatrix, renderFlags);
+
+    skBitmap->unlockPixels();
+}
+
+static JNINativeMethod gPdfRenderer_Methods[] = {
+    {"nativeCreate", "(IJ)J", (void*) nativeCreate},
+    {"nativeClose", "(J)V", (void*) nativeClose},
+    {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
+    {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
+    {"nativeRenderPage", "(JJJIIIIJI)V", (void*) nativeRenderPage},
+    {"nativeOpenPageAndGetSize", "(JILandroid/graphics/Point;)J", (void*) nativeOpenPageAndGetSize},
+    {"nativeClosePage", "(J)V", (void*) nativeClosePage}
+};
+
+int register_android_graphics_pdf_PdfRenderer(JNIEnv* env) {
+    int result = android::AndroidRuntime::registerNativeMethods(
+            env, "android/graphics/pdf/PdfRenderer", gPdfRenderer_Methods,
+            NELEM(gPdfRenderer_Methods));
+
+    jclass clazz = env->FindClass("android/graphics/Point");
+    gPointClassInfo.x = env->GetFieldID(clazz, "x", "I");
+    gPointClassInfo.y = env->GetFieldID(clazz, "y", "I");
+
+    return result;
+};
+
+};
diff --git a/core/jni/android_media_AudioErrors.h b/core/jni/android_media_AudioErrors.h
new file mode 100644
index 0000000..4907830
--- /dev/null
+++ b/core/jni/android_media_AudioErrors.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_MEDIA_AUDIOERRORS_H
+#define ANDROID_MEDIA_AUDIOERRORS_H
+
+#include <utils/Errors.h>
+
+namespace android {
+// status codes used by JAVA APIs. Translation from native error codes is done by
+// nativeToJavaStatus()
+// must be kept in sync with values in
+// frameworks/base/media/java/android/media/AudioSystem.java.
+enum {
+    AUDIO_JAVA_SUCCESS            = 0,
+    AUDIO_JAVA_ERROR              = -1,
+    AUDIO_JAVA_BAD_VALUE          = -2,
+    AUDIO_JAVA_INVALID_OPERATION  = -3,
+    AUDIO_JAVA_PERMISSION_DENIED  = -4,
+    AUDIO_JAVA_NO_INIT            = -5,
+    AUDIO_JAVA_DEAD_OBJECT        = -6,
+};
+
+static inline jint nativeToJavaStatus(status_t status) {
+    switch (status) {
+    case NO_ERROR:
+        return AUDIO_JAVA_SUCCESS;
+    case BAD_VALUE:
+        return AUDIO_JAVA_BAD_VALUE;
+    case INVALID_OPERATION:
+        return AUDIO_JAVA_INVALID_OPERATION;
+    case PERMISSION_DENIED:
+        return AUDIO_JAVA_PERMISSION_DENIED;
+    case NO_INIT:
+        return AUDIO_JAVA_NO_INIT;
+    case DEAD_OBJECT:
+        return AUDIO_JAVA_DEAD_OBJECT;
+    default:
+        return AUDIO_JAVA_ERROR;
+    }
+}
+}; // namespace android
+#endif // ANDROID_MEDIA_AUDIOERRORS_H
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 09bdc61..a54eba1 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -27,6 +27,7 @@
 #include <media/AudioRecord.h>
 
 #include "android_media_AudioFormat.h"
+#include "android_media_AudioErrors.h"
 
 // ----------------------------------------------------------------------------
 
@@ -55,29 +56,12 @@
 
 // ----------------------------------------------------------------------------
 
-#define AUDIORECORD_SUCCESS                         0
-#define AUDIORECORD_ERROR                           -1
-#define AUDIORECORD_ERROR_BAD_VALUE                 -2
-#define AUDIORECORD_ERROR_INVALID_OPERATION         -3
 #define AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT      -16
 #define AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK -17
 #define AUDIORECORD_ERROR_SETUP_INVALIDFORMAT       -18
 #define AUDIORECORD_ERROR_SETUP_INVALIDSOURCE       -19
 #define AUDIORECORD_ERROR_SETUP_NATIVEINITFAILED    -20
 
-jint android_media_translateRecorderErrorCode(int code) {
-    switch (code) {
-    case NO_ERROR:
-        return AUDIORECORD_SUCCESS;
-    case BAD_VALUE:
-        return AUDIORECORD_ERROR_BAD_VALUE;
-    case INVALID_OPERATION:
-        return AUDIORECORD_ERROR_INVALID_OPERATION;
-    default:
-        return AUDIORECORD_ERROR;
-    }
-}
-
 // ----------------------------------------------------------------------------
 static void recorderCallback(int event, void* user, void *info) {
 
@@ -197,13 +181,13 @@
 
     if (jSession == NULL) {
         ALOGE("Error creating AudioRecord: invalid session ID pointer");
-        return (jint) AUDIORECORD_ERROR;
+        return (jint) AUDIO_JAVA_ERROR;
     }
 
     jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
     if (nSession == NULL) {
         ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
-        return (jint) AUDIORECORD_ERROR;
+        return (jint) AUDIO_JAVA_ERROR;
     }
     int sessionId = nSession[0];
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
@@ -259,7 +243,7 @@
     // of the Java object (in mNativeCallbackCookie) so we can free the memory in finalize()
     env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, (jlong)lpCallbackData);
 
-    return (jint) AUDIORECORD_SUCCESS;
+    return (jint) AUDIO_JAVA_SUCCESS;
 
     // failure:
 native_init_failure:
@@ -280,10 +264,10 @@
     sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
     if (lpRecorder == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return (jint) AUDIORECORD_ERROR;
+        return (jint) AUDIO_JAVA_ERROR;
     }
 
-    return (jint) android_media_translateRecorderErrorCode(
+    return nativeToJavaStatus(
             lpRecorder->start((AudioSystem::sync_event_t)event, triggerSession));
 }
 
@@ -383,7 +367,7 @@
     env->ReleaseByteArrayElements(javaAudioData, recordBuff, 0);
 
     if (readSize < 0) {
-        readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+        readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
     }
     return (jint) readSize;
 }
@@ -428,7 +412,7 @@
     env->ReleaseShortArrayElements(javaAudioData, recordBuff, 0);
 
     if (readSize < 0) {
-        readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+        readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
     } else {
         readSize /= sizeof(short);
     }
@@ -461,7 +445,7 @@
     ssize_t readSize = lpRecorder->read(nativeFromJavaBuf,
                                    capacity < sizeInBytes ? capacity : sizeInBytes);
     if (readSize < 0) {
-        readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+        readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
     }
     return (jint)readSize;
 }
@@ -475,9 +459,9 @@
     if (lpRecorder == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioRecord pointer for setMarkerPosition()");
-        return AUDIORECORD_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateRecorderErrorCode( lpRecorder->setMarkerPosition(markerPos) );
+    return nativeToJavaStatus( lpRecorder->setMarkerPosition(markerPos) );
 }
 
 
@@ -490,7 +474,7 @@
     if (lpRecorder == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioRecord pointer for getMarkerPosition()");
-        return AUDIORECORD_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     lpRecorder->getMarkerPosition(&markerPos);
     return (jint)markerPos;
@@ -506,9 +490,9 @@
     if (lpRecorder == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioRecord pointer for setPositionUpdatePeriod()");
-        return AUDIORECORD_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateRecorderErrorCode( lpRecorder->setPositionUpdatePeriod(period) );
+    return nativeToJavaStatus( lpRecorder->setPositionUpdatePeriod(period) );
 }
 
 
@@ -521,7 +505,7 @@
     if (lpRecorder == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioRecord pointer for getPositionUpdatePeriod()");
-        return AUDIORECORD_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     lpRecorder->getPositionUpdatePeriod(&period);
     return (jint)period;
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 463a0a8..e548e91 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -32,6 +32,7 @@
 #include <binder/MemoryBase.h>
 
 #include "android_media_AudioFormat.h"
+#include "android_media_AudioErrors.h"
 
 // ----------------------------------------------------------------------------
 
@@ -94,31 +95,12 @@
 // ----------------------------------------------------------------------------
 #define DEFAULT_OUTPUT_SAMPLE_RATE   44100
 
-#define AUDIOTRACK_SUCCESS                         0
-#define AUDIOTRACK_ERROR                           -1
-#define AUDIOTRACK_ERROR_BAD_VALUE                 -2
-#define AUDIOTRACK_ERROR_INVALID_OPERATION         -3
 #define AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM         -16
 #define AUDIOTRACK_ERROR_SETUP_INVALIDCHANNELMASK  -17
 #define AUDIOTRACK_ERROR_SETUP_INVALIDFORMAT       -18
 #define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE   -19
 #define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED    -20
 
-
-jint android_media_translateErrorCode(int code) {
-    switch (code) {
-    case NO_ERROR:
-        return AUDIOTRACK_SUCCESS;
-    case BAD_VALUE:
-        return AUDIOTRACK_ERROR_BAD_VALUE;
-    case INVALID_OPERATION:
-        return AUDIOTRACK_ERROR_INVALID_OPERATION;
-    default:
-        return AUDIOTRACK_ERROR;
-    }
-}
-
-
 // ----------------------------------------------------------------------------
 static void audioCallback(int event, void* user, void *info) {
 
@@ -201,22 +183,6 @@
 {
     ALOGV("sampleRate=%d, audioFormat(from Java)=%d, channel mask=%x, buffSize=%d",
         sampleRateInHertz, audioFormat, javaChannelMask, buffSizeInBytes);
-    uint32_t afSampleRate;
-    size_t afFrameCount;
-
-    status_t status = AudioSystem::getOutputFrameCount(&afFrameCount,
-            (audio_stream_type_t) streamType);
-    if (status != NO_ERROR) {
-        ALOGE("Error %d creating AudioTrack: Could not get AudioSystem frame count "
-              "for stream type %d.", status, streamType);
-        return (jint) AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
-    }
-    status = AudioSystem::getOutputSamplingRate(&afSampleRate, (audio_stream_type_t) streamType);
-    if (status != NO_ERROR) {
-        ALOGE("Error %d creating AudioTrack: Could not get AudioSystem sampling rate "
-              "for stream type %d.", status, streamType);
-        return (jint) AUDIOTRACK_ERROR_SETUP_AUDIOSYSTEM;
-    }
 
     // Java channel masks don't map directly to the native definition, but it's a simple shift
     // to skip the two deprecated channel configurations "default" and "mono".
@@ -229,23 +195,8 @@
 
     uint32_t channelCount = popcount(nativeChannelMask);
 
-    // check the stream type
-    audio_stream_type_t atStreamType;
-    switch (streamType) {
-    case AUDIO_STREAM_VOICE_CALL:
-    case AUDIO_STREAM_SYSTEM:
-    case AUDIO_STREAM_RING:
-    case AUDIO_STREAM_MUSIC:
-    case AUDIO_STREAM_ALARM:
-    case AUDIO_STREAM_NOTIFICATION:
-    case AUDIO_STREAM_BLUETOOTH_SCO:
-    case AUDIO_STREAM_DTMF:
-        atStreamType = (audio_stream_type_t) streamType;
-        break;
-    default:
-        ALOGE("Error creating AudioTrack: unknown stream type %d.", streamType);
-        return (jint) AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE;
-    }
+    // stream type already checked in Java
+    audio_stream_type_t atStreamType = (audio_stream_type_t) streamType;
 
     // check the format.
     // This function was called from Java, so we compare the format against the Java constants
@@ -280,13 +231,13 @@
 
     if (jSession == NULL) {
         ALOGE("Error creating AudioTrack: invalid session ID pointer");
-        return (jint) AUDIOTRACK_ERROR;
+        return (jint) AUDIO_JAVA_ERROR;
     }
 
     jint* nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
     if (nSession == NULL) {
         ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
-        return (jint) AUDIOTRACK_ERROR;
+        return (jint) AUDIO_JAVA_ERROR;
     }
     int sessionId = nSession[0];
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
@@ -305,6 +256,7 @@
     lpJniStorage->mCallbackData.busy = false;
 
     // initialize the native AudioTrack object
+    status_t status = NO_ERROR;
     switch (memoryMode) {
     case MODE_STREAM:
 
@@ -376,7 +328,7 @@
     //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
     env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage);
 
-    return (jint) AUDIOTRACK_SUCCESS;
+    return (jint) AUDIO_JAVA_SUCCESS;
 
     // failures:
 native_init_failure:
@@ -626,7 +578,7 @@
     ScopedBytesRO bytes(env, javaBytes);
     if (bytes.get() == NULL) {
         ALOGE("Error retrieving source of audio data to play, can't play");
-        return AUDIOTRACK_ERROR_BAD_VALUE;
+        return (jint)AUDIO_JAVA_BAD_VALUE;
     }
 
     jint written = writeToTrack(lpTrack, javaAudioFormat, bytes.get(), byteOffset,
@@ -725,7 +677,7 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for frameCount()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
 
     return lpTrack->frameCount();
@@ -739,9 +691,9 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for setSampleRate()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateErrorCode(lpTrack->setSampleRate(sampleRateInHz));
+    return nativeToJavaStatus(lpTrack->setSampleRate(sampleRateInHz));
 }
 
 
@@ -751,7 +703,7 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for getSampleRate()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     return (jint) lpTrack->getSampleRate();
 }
@@ -764,9 +716,9 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for setMarkerPosition()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateErrorCode( lpTrack->setMarkerPosition(markerPos) );
+    return nativeToJavaStatus( lpTrack->setMarkerPosition(markerPos) );
 }
 
 
@@ -778,7 +730,7 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for getMarkerPosition()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     lpTrack->getMarkerPosition(&markerPos);
     return (jint)markerPos;
@@ -792,9 +744,9 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for setPositionUpdatePeriod()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateErrorCode( lpTrack->setPositionUpdatePeriod(period) );
+    return nativeToJavaStatus( lpTrack->setPositionUpdatePeriod(period) );
 }
 
 
@@ -806,7 +758,7 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for getPositionUpdatePeriod()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     lpTrack->getPositionUpdatePeriod(&period);
     return (jint)period;
@@ -820,9 +772,9 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for setPosition()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateErrorCode( lpTrack->setPosition(position) );
+    return nativeToJavaStatus( lpTrack->setPosition(position) );
 }
 
 
@@ -834,7 +786,7 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for getPosition()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     lpTrack->getPosition(&position);
     return (jint)position;
@@ -848,7 +800,7 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for latency()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     return (jint)lpTrack->latency();
 }
@@ -860,7 +812,7 @@
 
     if (lpTrack == NULL) {
         ALOGE("Unable to retrieve AudioTrack pointer for getTimestamp()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
     AudioTimestamp timestamp;
     status_t status = lpTrack->getTimestamp(timestamp);
@@ -868,13 +820,13 @@
         jlong* nTimestamp = (jlong *) env->GetPrimitiveArrayCritical(jTimestamp, NULL);
         if (nTimestamp == NULL) {
             ALOGE("Unable to get array for getTimestamp()");
-            return AUDIOTRACK_ERROR;
+            return (jint)AUDIO_JAVA_ERROR;
         }
         nTimestamp[0] = (jlong) timestamp.mPosition;
         nTimestamp[1] = (jlong) ((timestamp.mTime.tv_sec * 1000000000LL) + timestamp.mTime.tv_nsec);
         env->ReleasePrimitiveArrayCritical(jTimestamp, nTimestamp, 0);
     }
-    return (jint) android_media_translateErrorCode(status);
+    return (jint) nativeToJavaStatus(status);
 }
 
 
@@ -885,9 +837,9 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for setLoop()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateErrorCode( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
+    return nativeToJavaStatus( lpTrack->setLoop(loopStart, loopEnd, loopCount) );
 }
 
 
@@ -897,9 +849,9 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for reload()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateErrorCode( lpTrack->reload() );
+    return nativeToJavaStatus( lpTrack->reload() );
 }
 
 
@@ -982,9 +934,9 @@
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "Unable to retrieve AudioTrack pointer for attachAuxEffect()");
-        return AUDIOTRACK_ERROR;
+        return (jint)AUDIO_JAVA_ERROR;
     }
-    return android_media_translateErrorCode( lpTrack->attachAuxEffect(effectId) );
+    return nativeToJavaStatus( lpTrack->attachAuxEffect(effectId) );
 }
 
 // ----------------------------------------------------------------------------
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 662af89..d82fc96 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -697,6 +697,38 @@
             jniThrowException(env, "java/lang/RuntimeException",
                     "Not allowed to write file descriptors here");
             break;
+        case -EBADF:
+            jniThrowException(env, "java/lang/RuntimeException",
+                    "Bad file descriptor");
+            break;
+        case -ENFILE:
+            jniThrowException(env, "java/lang/RuntimeException",
+                    "File table overflow");
+            break;
+        case -EMFILE:
+            jniThrowException(env, "java/lang/RuntimeException",
+                    "Too many open files");
+            break;
+        case -EFBIG:
+            jniThrowException(env, "java/lang/RuntimeException",
+                    "File too large");
+            break;
+        case -ENOSPC:
+            jniThrowException(env, "java/lang/RuntimeException",
+                    "No space left on device");
+            break;
+        case -ESPIPE:
+            jniThrowException(env, "java/lang/RuntimeException",
+                    "Illegal seek");
+            break;
+        case -EROFS:
+            jniThrowException(env, "java/lang/RuntimeException",
+                    "Read-only file system");
+            break;
+        case -EMLINK:
+            jniThrowException(env, "java/lang/RuntimeException",
+                    "Too many links");
+            break;
         default:
             ALOGE("Unknown binder error code. 0x%" PRIx32, err);
             String8 msg;
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index e45a901..867c1b1 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -80,6 +80,7 @@
         jobject clazz, jlong renderNodePtr, jboolean caching) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setCaching(caching);
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setStaticMatrix(JNIEnv* env,
@@ -87,6 +88,7 @@
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
     renderNode->mutateStagingProperties().setStaticMatrix(matrix);
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setAnimationMatrix(JNIEnv* env,
@@ -94,24 +96,28 @@
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
     renderNode->mutateStagingProperties().setAnimationMatrix(matrix);
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setClipToBounds(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, jboolean clipToBounds) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setClipToBounds(clipToBounds);
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setProjectBackwards(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, jboolean shouldProject) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setProjectBackwards(shouldProject);
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setProjectionReceiver(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, jboolean shouldRecieve) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setProjectionReceiver(shouldRecieve);
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setOutlineRoundRect(JNIEnv* env,
@@ -119,6 +125,7 @@
         jint right, jint bottom, jfloat radius) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutableOutline().setRoundRect(left, top, right, bottom, radius);
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setOutlineConvexPath(JNIEnv* env,
@@ -126,18 +133,21 @@
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr);
     renderNode->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath);
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setOutlineEmpty(JNIEnv* env,
         jobject clazz, jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutableOutline().setEmpty();
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setClipToOutline(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, jboolean clipToOutline) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutableOutline().setShouldClip(clipToOutline);
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setRevealClip(JNIEnv* env,
@@ -146,114 +156,133 @@
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().mutableRevealClip().set(
             shouldClip, inverseClip, x, y, radius);
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setAlpha(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float alpha) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setAlpha(alpha);
+    renderNode->setPropertyFieldsDirty(RenderNode::ALPHA);
 }
 
 static void android_view_RenderNode_setHasOverlappingRendering(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, bool hasOverlappingRendering) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setHasOverlappingRendering(hasOverlappingRendering);
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setElevation(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float elevation) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setElevation(elevation);
+    renderNode->setPropertyFieldsDirty(RenderNode::Z);
 }
 
 static void android_view_RenderNode_setTranslationX(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float tx) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setTranslationX(tx);
+    renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_X | RenderNode::X);
 }
 
 static void android_view_RenderNode_setTranslationY(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float ty) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setTranslationY(ty);
+    renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_Y | RenderNode::Y);
 }
 
 static void android_view_RenderNode_setTranslationZ(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float tz) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setTranslationZ(tz);
+    renderNode->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z | RenderNode::Z);
 }
 
 static void android_view_RenderNode_setRotation(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float rotation) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setRotation(rotation);
+    renderNode->setPropertyFieldsDirty(RenderNode::ROTATION);
 }
 
 static void android_view_RenderNode_setRotationX(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float rx) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setRotationX(rx);
+    renderNode->setPropertyFieldsDirty(RenderNode::ROTATION_X);
 }
 
 static void android_view_RenderNode_setRotationY(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float ry) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setRotationY(ry);
+    renderNode->setPropertyFieldsDirty(RenderNode::ROTATION_Y);
 }
 
 static void android_view_RenderNode_setScaleX(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float sx) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setScaleX(sx);
+    renderNode->setPropertyFieldsDirty(RenderNode::SCALE_X);
 }
 
 static void android_view_RenderNode_setScaleY(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float sy) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setScaleY(sy);
+    renderNode->setPropertyFieldsDirty(RenderNode::SCALE_Y);
 }
 
 static void android_view_RenderNode_setPivotX(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float px) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setPivotX(px);
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setPivotY(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float py) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setPivotY(py);
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setCameraDistance(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float distance) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setCameraDistance(distance);
+    renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
 }
 
 static void android_view_RenderNode_setLeft(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, int left) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setLeft(left);
+    renderNode->setPropertyFieldsDirty(RenderNode::X);
 }
 
 static void android_view_RenderNode_setTop(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, int top) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setTop(top);
+    renderNode->setPropertyFieldsDirty(RenderNode::Y);
 }
 
 static void android_view_RenderNode_setRight(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, int right) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setRight(right);
+    renderNode->setPropertyFieldsDirty(RenderNode::X);
 }
 
 static void android_view_RenderNode_setBottom(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, int bottom) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setBottom(bottom);
+    renderNode->setPropertyFieldsDirty(RenderNode::Y);
 }
 
 static void android_view_RenderNode_setLeftTopRightBottom(JNIEnv* env,
@@ -261,18 +290,21 @@
         int right, int bottom) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().setLeftTopRightBottom(left, top, right, bottom);
+    renderNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
 }
 
 static void android_view_RenderNode_offsetLeftAndRight(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float offset) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().offsetLeftRight(offset);
+    renderNode->setPropertyFieldsDirty(RenderNode::X);
 }
 
 static void android_view_RenderNode_offsetTopAndBottom(JNIEnv* env,
         jobject clazz, jlong renderNodePtr, float offset) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
     renderNode->mutateStagingProperties().offsetTopBottom(offset);
+    renderNode->setPropertyFieldsDirty(RenderNode::Y);
 }
 
 // ----------------------------------------------------------------------------
@@ -285,6 +317,12 @@
     return renderNode->stagingProperties().hasOverlappingRendering();
 }
 
+static jboolean android_view_RenderNode_getClipToOutline(JNIEnv* env,
+        jobject clazz, jlong renderNodePtr) {
+    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
+    return renderNode->stagingProperties().getOutline().getShouldClip();
+}
+
 static jfloat android_view_RenderNode_getAlpha(JNIEnv* env,
         jobject clazz, jlong renderNodePtr) {
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
@@ -505,6 +543,7 @@
     { "nOffsetTopAndBottom",   "(JF)V",  (void*) android_view_RenderNode_offsetTopAndBottom },
 
     { "nHasOverlappingRendering", "(J)Z",  (void*) android_view_RenderNode_hasOverlappingRendering },
+    { "nGetClipToOutline",        "(J)Z",  (void*) android_view_RenderNode_getClipToOutline },
     { "nGetAlpha",                "(J)F",  (void*) android_view_RenderNode_getAlpha },
     { "nGetLeft",                 "(J)F",  (void*) android_view_RenderNode_getLeft },
     { "nGetTop",                  "(J)F",  (void*) android_view_RenderNode_getTop },
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index 5733f60..e19ce36 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -62,7 +62,7 @@
         mWeakThis = NULL;
     }
 
-    virtual void onAnimationFinished(BaseAnimator*) {
+    virtual void onAnimationFinished(BaseRenderNodeAnimator*) {
         JNIEnv* env = getEnv(mJvm);
         env->CallStaticVoidMethod(
                 gRenderNodeAnimatorClassInfo.clazz,
@@ -81,13 +81,6 @@
     return static_cast<RenderPropertyAnimator::RenderProperty>(property);
 }
 
-static inline RenderPropertyAnimator::DeltaValueType toDeltaType(jint deltaType) {
-    LOG_ALWAYS_FATAL_IF(deltaType != RenderPropertyAnimator::DELTA
-            && deltaType != RenderPropertyAnimator::ABSOLUTE,
-            "Invalid delta type %d", deltaType);
-    return static_cast<RenderPropertyAnimator::DeltaValueType>(deltaType);
-}
-
 static inline CanvasPropertyPaintAnimator::PaintField toPaintField(jint field) {
     LOG_ALWAYS_FATAL_IF(field < 0
             || field > CanvasPropertyPaintAnimator::ALPHA,
@@ -96,49 +89,57 @@
 }
 
 static jlong createAnimator(JNIEnv* env, jobject clazz, jobject weakThis,
-        jint propertyRaw, jint deltaTypeRaw, jfloat deltaValue) {
+        jint propertyRaw, jfloat finalValue) {
     RenderPropertyAnimator::RenderProperty property = toRenderProperty(propertyRaw);
-    RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
 
-    BaseAnimator* animator = new RenderPropertyAnimator(property, deltaType, deltaValue);
+    BaseRenderNodeAnimator* animator = new RenderPropertyAnimator(property, finalValue);
     animator->setListener(new AnimationListenerBridge(env, weakThis));
     return reinterpret_cast<jlong>( animator );
 }
 
 static jlong createCanvasPropertyFloatAnimator(JNIEnv* env, jobject clazz,
-        jobject weakThis, jlong canvasPropertyPtr, jint deltaTypeRaw, jfloat deltaValue) {
-    RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
+        jobject weakThis, jlong canvasPropertyPtr, jfloat finalValue) {
     CanvasPropertyPrimitive* canvasProperty = reinterpret_cast<CanvasPropertyPrimitive*>(canvasPropertyPtr);
-    BaseAnimator* animator = new CanvasPropertyPrimitiveAnimator(canvasProperty, deltaType, deltaValue);
+    BaseRenderNodeAnimator* animator = new CanvasPropertyPrimitiveAnimator(canvasProperty, finalValue);
     animator->setListener(new AnimationListenerBridge(env, weakThis));
     return reinterpret_cast<jlong>( animator );
 }
 
 static jlong createCanvasPropertyPaintAnimator(JNIEnv* env, jobject clazz,
         jobject weakThis, jlong canvasPropertyPtr, jint paintFieldRaw,
-        jint deltaTypeRaw, jfloat deltaValue) {
-    RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
+        jfloat finalValue) {
     CanvasPropertyPaint* canvasProperty = reinterpret_cast<CanvasPropertyPaint*>(canvasPropertyPtr);
     CanvasPropertyPaintAnimator::PaintField paintField = toPaintField(paintFieldRaw);
-    BaseAnimator* animator = new CanvasPropertyPaintAnimator(
-            canvasProperty, paintField, deltaType, deltaValue);
+    BaseRenderNodeAnimator* animator = new CanvasPropertyPaintAnimator(
+            canvasProperty, paintField, finalValue);
     animator->setListener(new AnimationListenerBridge(env, weakThis));
     return reinterpret_cast<jlong>( animator );
 }
 
-static void setDuration(JNIEnv* env, jobject clazz, jlong animatorPtr, jint duration) {
+static void setDuration(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong duration) {
     LOG_ALWAYS_FATAL_IF(duration < 0, "Duration cannot be negative");
-    BaseAnimator* animator = reinterpret_cast<BaseAnimator*>(animatorPtr);
+    BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
     animator->setDuration(duration);
 }
 
-static jint getDuration(JNIEnv* env, jobject clazz, jlong animatorPtr) {
-    BaseAnimator* animator = reinterpret_cast<BaseAnimator*>(animatorPtr);
-    return static_cast<jint>(animator->duration());
+static jlong getDuration(JNIEnv* env, jobject clazz, jlong animatorPtr) {
+    BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
+    return static_cast<jlong>(animator->duration());
+}
+
+static void setStartDelay(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong startDelay) {
+    LOG_ALWAYS_FATAL_IF(startDelay < 0, "Start delay cannot be negative");
+    BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
+    animator->setStartDelay(startDelay);
+}
+
+static jlong getStartDelay(JNIEnv* env, jobject clazz, jlong animatorPtr) {
+    BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
+    return static_cast<jlong>(animator->startDelay());
 }
 
 static void setInterpolator(JNIEnv* env, jobject clazz, jlong animatorPtr, jlong interpolatorPtr) {
-    BaseAnimator* animator = reinterpret_cast<BaseAnimator*>(animatorPtr);
+    BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
     Interpolator* interpolator = reinterpret_cast<Interpolator*>(interpolatorPtr);
     animator->setInterpolator(interpolator);
 }
@@ -153,11 +154,13 @@
 
 static JNINativeMethod gMethods[] = {
 #ifdef USE_OPENGL_RENDERER
-    { "nCreateAnimator", "(Ljava/lang/ref/WeakReference;IIF)J", (void*) createAnimator },
-    { "nCreateCanvasPropertyFloatAnimator", "(Ljava/lang/ref/WeakReference;JIF)J", (void*) createCanvasPropertyFloatAnimator },
-    { "nCreateCanvasPropertyPaintAnimator", "(Ljava/lang/ref/WeakReference;JIIF)J", (void*) createCanvasPropertyPaintAnimator },
-    { "nSetDuration", "(JI)V", (void*) setDuration },
-    { "nGetDuration", "(J)I", (void*) getDuration },
+    { "nCreateAnimator", "(Ljava/lang/ref/WeakReference;IF)J", (void*) createAnimator },
+    { "nCreateCanvasPropertyFloatAnimator", "(Ljava/lang/ref/WeakReference;JF)J", (void*) createCanvasPropertyFloatAnimator },
+    { "nCreateCanvasPropertyPaintAnimator", "(Ljava/lang/ref/WeakReference;JIF)J", (void*) createCanvasPropertyPaintAnimator },
+    { "nSetDuration", "(JJ)V", (void*) setDuration },
+    { "nGetDuration", "(J)J", (void*) getDuration },
+    { "nSetStartDelay", "(JJ)V", (void*) setStartDelay },
+    { "nGetStartDelay", "(J)J", (void*) getStartDelay },
     { "nSetInterpolator", "(JJ)V", (void*) setInterpolator },
 #endif
 };
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index d130a6d..2c10212 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -92,9 +92,9 @@
 
 class OnFinishedEvent {
 public:
-    OnFinishedEvent(BaseAnimator* animator, AnimationListener* listener)
+    OnFinishedEvent(BaseRenderNodeAnimator* animator, AnimationListener* listener)
             : animator(animator), listener(listener) {}
-    sp<BaseAnimator> animator;
+    sp<BaseRenderNodeAnimator> animator;
     sp<AnimationListener> listener;
 };
 
@@ -127,7 +127,7 @@
 
     virtual ~RootRenderNode() {}
 
-    virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) {
+    virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
         OnFinishedEvent event(animator, listener);
         mOnFinishedEvents.push_back(event);
     }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index cdb77f1..f262a93 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2056,7 +2056,7 @@
         android:protectionLevel="signature|system" />
 
     <!-- Must be required by a {@link android.service.voice.VoiceInteractionService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it. @hide -->
     <permission android:name="android.permission.BIND_VOICE_INTERACTION"
         android:label="@string/permlab_bindVoiceInteraction"
         android:description="@string/permdesc_bindVoiceInteraction"
@@ -2613,7 +2613,7 @@
     <!-- Must be required by an {@link
          android.service.trust.TrustAgentService},
          to ensure that only the system can bind to it. -->
-    <permission android:name="android.permission.BIND_TRUST_AGENT_SERVICE"
+    <permission android:name="android.permission.BIND_TRUST_AGENT"
                 android:protectionLevel="signature"
                 android:label="@string/permlab_bind_trust_agent_service"
                 android:description="@string/permdesc_bind_trust_agent_service" />
diff --git a/core/res/res/layout/notification_action.xml b/core/res/res/layout/notification_action.xml
deleted file mode 100644
index 4e7c74c..0000000
--- a/core/res/res/layout/notification_action.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<Button xmlns:android="http://schemas.android.com/apk/res/android"
-    style="?android:attr/borderlessButtonStyle" 
-    android:id="@+id/action0"
-    android:layout_width="0dp"
-    android:layout_height="48dp"
-    android:layout_weight="1"
-    android:gravity="start|center_vertical"
-    android:drawablePadding="8dp"
-    android:paddingStart="8dp"
-    android:textColor="#ccc"
-    android:textSize="14dp"
-    android:singleLine="true"
-    android:ellipsize="end"
-    />
diff --git a/core/res/res/layout/notification_action_tombstone.xml b/core/res/res/layout/notification_action_tombstone.xml
deleted file mode 100644
index 9977cfe..0000000
--- a/core/res/res/layout/notification_action_tombstone.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<Button xmlns:android="http://schemas.android.com/apk/res/android"
-    style="?android:attr/borderlessButtonStyle" 
-    android:id="@+id/action0"
-    android:layout_width="0dp"
-    android:layout_height="48dp"
-    android:layout_weight="1"
-    android:gravity="start|center_vertical"
-    android:drawablePadding="8dp"
-    android:paddingStart="8dp"
-    android:textColor="#ccc"
-    android:textSize="14dp"
-    android:singleLine="true"
-    android:ellipsize="end"
-    android:alpha="0.5"
-    android:enabled="false"
-    />
diff --git a/core/res/res/layout/notification_template_base.xml b/core/res/res/layout/notification_template_base.xml
deleted file mode 100644
index d2e25c1..0000000
--- a/core/res/res/layout/notification_template_base.xml
+++ /dev/null
@@ -1,136 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:background="@android:drawable/notification_bg"
-    android:id="@+id/status_bar_latest_event_content"
-    android:layout_width="match_parent"
-    android:layout_height="64dp"
-    internal:layout_minHeight="64dp"
-    internal:layout_maxHeight="64dp"
-    >
-    <ImageView android:id="@+id/icon"
-        android:layout_width="@dimen/notification_large_icon_width"
-        android:layout_height="@dimen/notification_large_icon_height"
-        android:background="@android:drawable/notification_template_icon_bg"
-        android:scaleType="center"
-        />
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="fill_vertical"
-        android:layout_marginStart="@dimen/notification_large_icon_width"
-        android:minHeight="@dimen/notification_large_icon_height"
-        android:orientation="vertical"
-        android:paddingEnd="8dp"
-        android:paddingTop="2dp"
-        android:paddingBottom="2dp"
-        android:gravity="top"
-        >
-        <LinearLayout
-            android:id="@+id/line1"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="6dp"
-            android:layout_marginStart="8dp"
-            android:orientation="horizontal"
-            >
-            <TextView android:id="@+id/title"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:singleLine="true"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                android:layout_weight="1"
-                />
-            <ViewStub android:id="@+id/time"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_weight="0"
-                android:visibility="gone"
-                android:layout="@layout/notification_template_part_time"
-                />
-            <ViewStub android:id="@+id/chronometer"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_weight="0"
-                android:visibility="gone"
-                android:layout="@layout/notification_template_part_chronometer"
-                />
-        </LinearLayout>
-        <TextView android:id="@+id/text2"
-            android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="-2dp"
-            android:layout_marginBottom="-2dp"
-            android:layout_marginStart="8dp"
-            android:singleLine="true"
-            android:fadingEdge="horizontal"
-            android:ellipsize="marquee"
-            android:visibility="gone"
-            />
-        <ProgressBar
-            android:id="@android:id/progress"
-            android:layout_width="match_parent"
-            android:layout_height="12dp"
-            android:layout_marginStart="8dp"
-            android:visibility="gone"
-            style="?android:attr/progressBarStyleHorizontal"
-            />
-        <LinearLayout
-            android:id="@+id/line3"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:gravity="center_vertical"
-            android:layout_marginStart="8dp"
-            >
-            <TextView android:id="@+id/text"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:layout_gravity="center"
-                android:singleLine="true"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                />
-            <TextView android:id="@+id/info"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:singleLine="true"
-                android:gravity="center"
-                android:paddingStart="8dp"
-                />
-            <ImageView android:id="@+id/right_icon"
-                android:layout_width="16dp"
-                android:layout_height="16dp"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:layout_marginStart="8dp"
-                android:scaleType="centerInside"
-                android:visibility="gone"
-                android:drawableAlpha="153"
-                />
-        </LinearLayout>
-    </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_base.xml b/core/res/res/layout/notification_template_big_base.xml
deleted file mode 100644
index 7cc6650..0000000
--- a/core/res/res/layout/notification_template_big_base.xml
+++ /dev/null
@@ -1,167 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:background="@android:drawable/notification_bg"
-    android:id="@+id/status_bar_latest_event_content"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    internal:layout_minHeight="65dp"
-    internal:layout_maxHeight="unbounded"
-    >
-    <ImageView android:id="@+id/icon"
-        android:layout_width="@dimen/notification_large_icon_width"
-        android:layout_height="@dimen/notification_large_icon_height"
-        android:background="@android:drawable/notification_template_icon_bg"
-        android:scaleType="center"
-        />
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="fill_vertical"
-        android:minHeight="@dimen/notification_large_icon_height"
-        android:orientation="vertical"
-        android:gravity="top"
-        >
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="@dimen/notification_large_icon_width"
-            android:minHeight="@dimen/notification_large_icon_height"
-            android:paddingTop="2dp"
-            android:orientation="vertical"
-            >
-            <LinearLayout
-                android:id="@+id/line1"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:paddingTop="6dp"
-                android:layout_marginEnd="8dp"
-                android:layout_marginStart="8dp"
-                android:orientation="horizontal"
-                >
-                <TextView android:id="@+id/title"
-                    android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:singleLine="true"
-                    android:ellipsize="marquee"
-                    android:fadingEdge="horizontal"
-                    android:layout_weight="1"
-                    />
-                <ViewStub android:id="@+id/time"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="0"
-                    android:visibility="gone"
-                    android:layout="@layout/notification_template_part_time"
-                    />
-                <ViewStub android:id="@+id/chronometer"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="0"
-                    android:visibility="gone"
-                    android:layout="@layout/notification_template_part_chronometer"
-                    />
-            </LinearLayout>
-            <TextView android:id="@+id/text2"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="-2dp"
-                android:layout_marginBottom="-2dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:fadingEdge="horizontal"
-                android:ellipsize="marquee"
-                android:visibility="gone"
-                />
-            <TextView android:id="@+id/big_text"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="false"
-                android:visibility="gone"
-                />
-            <LinearLayout
-                android:id="@+id/line3"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:orientation="horizontal"
-                android:gravity="center_vertical"
-                >
-                <TextView android:id="@+id/text"
-                    android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                    android:layout_width="0dp"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1"
-                    android:layout_gravity="center"
-                    android:singleLine="true"
-                    android:ellipsize="marquee"
-                    android:fadingEdge="horizontal"
-                    />
-                <TextView android:id="@+id/info"
-                    android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
-                    android:layout_weight="0"
-                    android:singleLine="true"
-                    android:gravity="center"
-                    android:paddingStart="8dp"
-                    />
-                <ImageView android:id="@+id/right_icon"
-                    android:layout_width="16dp"
-                    android:layout_height="16dp"
-                    android:layout_gravity="center"
-                    android:layout_weight="0"
-                    android:layout_marginStart="8dp"
-                    android:scaleType="centerInside"
-                    android:visibility="gone"
-                    android:drawableAlpha="153"
-                    />
-            </LinearLayout>
-            <ProgressBar
-                android:id="@android:id/progress"
-                android:layout_width="match_parent"
-                android:layout_height="12dp"
-                android:layout_marginBottom="8dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:visibility="gone"
-                style="?android:attr/progressBarStyleHorizontal"
-                />
-        </LinearLayout>
-        <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="1px"
-            android:id="@+id/action_divider"
-            android:visibility="gone"
-            android:background="?android:attr/dividerHorizontal" />
-        <include
-            layout="@layout/notification_action_list"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="@dimen/notification_large_icon_width"
-            />
-    </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_picture.xml b/core/res/res/layout/notification_template_big_picture.xml
deleted file mode 100644
index f3f3951..0000000
--- a/core/res/res/layout/notification_template_big_picture.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:background="@android:drawable/notification_bg"
-    android:id="@+id/status_bar_latest_event_content"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    internal:layout_minHeight="65dp"
-    internal:layout_maxHeight="unbounded"
-    >
-    <ImageView
-        android:id="@+id/big_picture"
-        android:layout_width="match_parent"
-        android:layout_height="192dp"
-        android:layout_marginTop="64dp"
-        android:layout_gravity="bottom"
-        android:scaleType="centerCrop"
-        />
-    <ImageView
-        android:layout_width="match_parent"
-        android:layout_height="6dp"
-        android:layout_marginTop="64dp"
-        android:scaleType="fitXY"
-        android:src="@drawable/title_bar_shadow"
-        />
-    <include layout="@layout/notification_template_base"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        />
-  <FrameLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="208dp"
-        android:paddingStart="64dp"
-        android:layout_gravity="bottom"
-        android:background="#CC111111"
-        >
-        <include
-            layout="@layout/notification_action_list"
-            android:id="@+id/actions"
-            android:layout_gravity="bottom"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            />
-    </FrameLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_text.xml b/core/res/res/layout/notification_template_big_text.xml
deleted file mode 100644
index 7e6da22..0000000
--- a/core/res/res/layout/notification_template_big_text.xml
+++ /dev/null
@@ -1,183 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:background="@android:drawable/notification_bg"
-    android:id="@+id/status_bar_latest_event_content"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    internal:layout_minHeight="65dp"
-    internal:layout_maxHeight="unbounded"
-    >
-    <ImageView android:id="@+id/icon"
-        android:layout_width="@dimen/notification_large_icon_width"
-        android:layout_height="@dimen/notification_large_icon_height"
-        android:background="@android:drawable/notification_template_icon_bg"
-        android:scaleType="center"
-        />
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="fill_vertical"
-        android:layout_marginStart="@dimen/notification_large_icon_width"
-        android:orientation="vertical"
-        android:paddingTop="0dp"
-        android:paddingBottom="2dp"
-        android:gravity="top"
-        >
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:minHeight="@dimen/notification_large_icon_height"
-            android:orientation="vertical"
-            android:layout_marginStart="8dp"
-            android:layout_marginEnd="8dp"
-            android:layout_weight="1"
-            >
-            <LinearLayout
-                android:id="@+id/line1"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:paddingTop="8dp"
-                android:orientation="horizontal"
-                android:layout_gravity="top"
-                android:layout_weight="0"
-                >
-                <TextView android:id="@+id/title"
-                    android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:singleLine="true"
-                    android:ellipsize="marquee"
-                    android:fadingEdge="horizontal"
-                    android:layout_weight="1"
-                    />
-                <ViewStub android:id="@+id/time"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="0"
-                    android:visibility="gone"
-                    android:layout="@layout/notification_template_part_time"
-                    />
-                <ViewStub android:id="@+id/chronometer"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="0"
-                    android:visibility="gone"
-                    android:layout="@layout/notification_template_part_chronometer"
-                    />
-            </LinearLayout>
-            <TextView android:id="@+id/text2"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="-2dp"
-                android:layout_marginBottom="-2dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:fadingEdge="horizontal"
-                android:ellipsize="marquee"
-                android:layout_weight="0"
-                android:visibility="gone"
-                />
-            <ProgressBar
-                android:id="@android:id/progress"
-                android:layout_width="match_parent"
-                android:layout_height="12dp"
-                android:layout_marginBottom="8dp"
-                android:layout_marginEnd="8dp"
-                android:visibility="gone"
-                android:layout_weight="0"
-                style="?android:attr/progressBarStyleHorizontal"
-                />
-            <TextView android:id="@+id/big_text"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginBottom="10dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="false"
-                android:visibility="gone"
-                android:maxLines="8"
-                android:ellipsize="end"
-                android:layout_weight="1"
-                />
-        </LinearLayout>
-        <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="1dip"
-            android:layout_marginTop="-1px"
-            android:id="@+id/action_divider"
-            android:visibility="gone"
-            android:background="?android:attr/dividerHorizontal" />
-        <include
-            layout="@layout/notification_action_list"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:visibility="gone"
-            android:layout_weight="1"
-            />
-        <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="1px"
-            android:id="@+id/overflow_divider"
-            android:layout_marginBottom="8dp"
-            android:visibility="visible"
-            android:background="?android:attr/dividerHorizontal" />
-        <LinearLayout
-            android:id="@+id/line3"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="8dp"
-            android:layout_marginBottom="8dp"
-            android:layout_marginEnd="8dp"
-            android:orientation="horizontal"
-            android:layout_weight="0"
-            android:gravity="center_vertical"
-            >
-            <TextView android:id="@+id/text"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:layout_gravity="center"
-                android:singleLine="true"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                />
-            <TextView android:id="@+id/info"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:singleLine="true"
-                android:gravity="center"
-                android:paddingStart="8dp"
-                />
-            <ImageView android:id="@+id/right_icon"
-                android:layout_width="16dp"
-                android:layout_height="16dp"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:layout_marginStart="8dp"
-                android:scaleType="centerInside"
-                android:visibility="gone"
-                android:drawableAlpha="153"
-                />
-        </LinearLayout>
-    </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_icon_group.xml b/core/res/res/layout/notification_template_icon_group.xml
new file mode 100644
index 0000000..2ad6f9e
--- /dev/null
+++ b/core/res/res/layout/notification_template_icon_group.xml
@@ -0,0 +1,42 @@
+<?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
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+    android:layout_width="@dimen/notification_large_icon_width"
+    android:layout_height="@dimen/notification_large_icon_height"
+    android:id="@+id/icon_group"
+    >
+    <ImageView android:id="@+id/icon"
+        android:layout_width="@dimen/notification_large_icon_width"
+        android:layout_height="@dimen/notification_large_icon_height"
+        android:padding="8dp"
+        android:scaleType="centerInside"
+        />
+    <ImageView android:id="@+id/right_icon"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:padding="4dp"
+        android:layout_gravity="end|bottom"
+        android:scaleType="centerInside"
+        android:visibility="gone"
+        android:layout_marginEnd="3dp"
+        android:layout_marginBottom="3dp"
+        />
+</FrameLayout>
+
diff --git a/core/res/res/layout/notification_template_inbox.xml b/core/res/res/layout/notification_template_inbox.xml
deleted file mode 100644
index 1eec871..0000000
--- a/core/res/res/layout/notification_template_inbox.xml
+++ /dev/null
@@ -1,267 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:internal="http://schemas.android.com/apk/prv/res/android"
-    android:id="@+id/status_bar_latest_event_content"
-    android:background="@android:drawable/notification_bg"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    internal:layout_minHeight="65dp"
-    internal:layout_maxHeight="unbounded"
-    >
-    <ImageView android:id="@+id/icon"
-        android:layout_width="@dimen/notification_large_icon_width"
-        android:layout_height="@dimen/notification_large_icon_height"
-        android:background="@android:drawable/notification_template_icon_bg"
-        android:scaleType="center"
-        />
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="fill_vertical"
-        android:layout_marginStart="@dimen/notification_large_icon_width"
-        android:minHeight="@dimen/notification_large_icon_height"
-        android:orientation="vertical"
-        android:paddingTop="0dp"
-        android:paddingBottom="2dp"
-        android:gravity="top"
-        >
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:minHeight="@dimen/notification_large_icon_height"
-            android:paddingTop="2dp"
-            android:orientation="vertical"
-            >
-            <LinearLayout
-                android:id="@+id/line1"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:paddingTop="6dp"
-                android:orientation="horizontal"
-                android:layout_weight="0"
-                >
-                <TextView android:id="@+id/title"
-                    android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:singleLine="true"
-                    android:ellipsize="marquee"
-                    android:fadingEdge="horizontal"
-                    android:layout_weight="1"
-                    />
-                <ViewStub android:id="@+id/time"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="0"
-                    android:visibility="gone"
-                    android:layout="@layout/notification_template_part_time"
-                    />
-                <ViewStub android:id="@+id/chronometer"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="0"
-                    android:visibility="gone"
-                    android:layout="@layout/notification_template_part_chronometer"
-                    />
-            </LinearLayout>
-            <TextView android:id="@+id/text2"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="-2dp"
-                android:layout_marginBottom="-2dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:fadingEdge="horizontal"
-                android:ellipsize="marquee"
-                android:visibility="gone"
-                android:layout_weight="0"
-                />
-            <ProgressBar
-                android:id="@android:id/progress"
-                android:layout_width="match_parent"
-                android:layout_height="12dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:visibility="gone"
-                android:layout_weight="0"
-                style="?android:attr/progressBarStyleHorizontal"
-                />
-            <TextView android:id="@+id/inbox_text0"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <TextView android:id="@+id/inbox_text1"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <TextView android:id="@+id/inbox_text2"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <TextView android:id="@+id/inbox_text3"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <TextView android:id="@+id/inbox_text4"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <TextView android:id="@+id/inbox_text5"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <TextView android:id="@+id/inbox_text6"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                />
-            <TextView android:id="@+id/inbox_more"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_marginStart="8dp"
-                android:layout_marginEnd="8dp"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:visibility="gone"
-                android:layout_weight="1"
-                android:text="@android:string/ellipsis"
-                />
-            <FrameLayout 
-                android:id="@+id/inbox_end_pad"
-                android:layout_width="match_parent"
-                android:layout_height="8dip"
-                android:visibility="gone"
-                android:layout_weight="0"
-            />
-        </LinearLayout>
-        <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="1dip"
-            android:layout_marginTop="-1px"
-            android:id="@+id/action_divider"
-            android:background="?android:attr/dividerHorizontal" />
-        <include
-            layout="@layout/notification_action_list"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_weight="0"
-            />
-        <ImageView
-            android:layout_width="match_parent"
-            android:layout_height="1dip"
-            android:layout_marginTop="-1px"
-            android:id="@+id/overflow_divider"
-            android:visibility="visible"
-            android:background="?android:attr/dividerHorizontal" />
-        <LinearLayout
-            android:id="@+id/line3"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="8dp"
-            android:layout_marginStart="8dp"
-            android:layout_marginBottom="8dp"
-            android:layout_marginEnd="8dp"
-            android:orientation="horizontal"
-            android:layout_weight="0"
-            android:gravity="center_vertical"
-            >
-            <TextView android:id="@+id/text"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
-                android:layout_width="0dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"
-                android:layout_gravity="center"
-                android:singleLine="true"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                />
-            <TextView android:id="@+id/info"
-                android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:singleLine="true"
-                android:gravity="center"
-                android:paddingStart="8dp"
-                />
-            <ImageView android:id="@+id/right_icon"
-                android:layout_width="16dp"
-                android:layout_height="16dp"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:layout_marginStart="8dp"
-                android:scaleType="centerInside"
-                android:visibility="gone"
-                android:drawableAlpha="153"
-                />
-        </LinearLayout>
-    </LinearLayout>
-</FrameLayout>
diff --git a/core/res/res/layout/notification_template_quantum_base.xml b/core/res/res/layout/notification_template_quantum_base.xml
index 8f3019d..789bf32 100644
--- a/core/res/res/layout/notification_template_quantum_base.xml
+++ b/core/res/res/layout/notification_template_quantum_base.xml
@@ -23,10 +23,9 @@
     internal:layout_minHeight="64dp"
     internal:layout_maxHeight="64dp"
     >
-    <ImageView android:id="@+id/icon"
+    <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
         android:layout_height="@dimen/notification_large_icon_height"
-        android:scaleType="center"
         />
     <LinearLayout
         android:layout_width="match_parent"
@@ -91,7 +90,7 @@
             android:layout_height="12dp"
             android:layout_marginStart="8dp"
             android:visibility="gone"
-            style="@style/Widget.Quantum.Light.ProgressBar.Horizontal"
+            style="@style/Widget.StatusBar.Quantum.ProgressBar"
             />
         <LinearLayout
             android:id="@+id/line3"
@@ -121,16 +120,6 @@
                 android:gravity="center"
                 android:paddingStart="8dp"
                 />
-            <ImageView android:id="@+id/right_icon"
-                android:layout_width="16dp"
-                android:layout_height="16dp"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:layout_marginStart="8dp"
-                android:scaleType="centerInside"
-                android:visibility="gone"
-                android:drawableAlpha="153"
-                />
         </LinearLayout>
     </LinearLayout>
 </FrameLayout>
diff --git a/core/res/res/layout/notification_template_quantum_big_base.xml b/core/res/res/layout/notification_template_quantum_big_base.xml
index 45e69b1..8cb5549 100644
--- a/core/res/res/layout/notification_template_quantum_big_base.xml
+++ b/core/res/res/layout/notification_template_quantum_big_base.xml
@@ -23,10 +23,9 @@
     internal:layout_minHeight="65dp"
     internal:layout_maxHeight="unbounded"
     >
-    <ImageView android:id="@+id/icon"
+    <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
         android:layout_height="@dimen/notification_large_icon_height"
-        android:scaleType="center"
         />
     <LinearLayout
         android:layout_width="match_parent"
@@ -128,16 +127,6 @@
                     android:gravity="center"
                     android:paddingStart="8dp"
                     />
-                <ImageView android:id="@+id/right_icon"
-                    android:layout_width="16dp"
-                    android:layout_height="16dp"
-                    android:layout_gravity="center"
-                    android:layout_weight="0"
-                    android:layout_marginStart="8dp"
-                    android:scaleType="centerInside"
-                    android:visibility="gone"
-                    android:drawableAlpha="153"
-                    />
             </LinearLayout>
             <ProgressBar
                 android:id="@android:id/progress"
diff --git a/core/res/res/layout/notification_template_quantum_big_text.xml b/core/res/res/layout/notification_template_quantum_big_text.xml
index f7769d7..bbd1071 100644
--- a/core/res/res/layout/notification_template_quantum_big_text.xml
+++ b/core/res/res/layout/notification_template_quantum_big_text.xml
@@ -22,10 +22,9 @@
     internal:layout_minHeight="65dp"
     internal:layout_maxHeight="unbounded"
     >
-    <ImageView android:id="@+id/icon"
+    <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
         android:layout_height="@dimen/notification_large_icon_height"
-        android:scaleType="center"
         />
     <LinearLayout
         android:layout_width="match_parent"
@@ -166,16 +165,6 @@
                 android:gravity="center"
                 android:paddingStart="8dp"
                 />
-            <ImageView android:id="@+id/right_icon"
-                android:layout_width="16dp"
-                android:layout_height="16dp"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:layout_marginStart="8dp"
-                android:scaleType="centerInside"
-                android:visibility="gone"
-                android:drawableAlpha="153"
-                />
         </LinearLayout>
     </LinearLayout>
 </FrameLayout>
diff --git a/core/res/res/layout/notification_template_quantum_inbox.xml b/core/res/res/layout/notification_template_quantum_inbox.xml
index 04974c4..a071d59 100644
--- a/core/res/res/layout/notification_template_quantum_inbox.xml
+++ b/core/res/res/layout/notification_template_quantum_inbox.xml
@@ -23,10 +23,9 @@
     internal:layout_minHeight="65dp"
     internal:layout_maxHeight="unbounded"
     >
-    <ImageView android:id="@+id/icon"
+    <include layout="@layout/notification_template_icon_group"
         android:layout_width="@dimen/notification_large_icon_width"
         android:layout_height="@dimen/notification_large_icon_height"
-        android:scaleType="center"
         />
     <LinearLayout
         android:layout_width="match_parent"
@@ -250,16 +249,6 @@
                 android:gravity="center"
                 android:paddingStart="8dp"
                 />
-            <ImageView android:id="@+id/right_icon"
-                android:layout_width="16dp"
-                android:layout_height="16dp"
-                android:layout_gravity="center"
-                android:layout_weight="0"
-                android:layout_marginStart="8dp"
-                android:scaleType="centerInside"
-                android:visibility="gone"
-                android:drawableAlpha="153"
-                />
         </LinearLayout>
     </LinearLayout>
 </FrameLayout>
diff --git a/core/res/res/layout/status_bar_latest_event_content.xml b/core/res/res/layout/status_bar_latest_event_content.xml
index b3db01a..dc78174 100644
--- a/core/res/res/layout/status_bar_latest_event_content.xml
+++ b/core/res/res/layout/status_bar_latest_event_content.xml
@@ -22,7 +22,7 @@
     android:layout_height="wrap_content"
     android:background="#FFFF00FF"
     >
-    <include layout="@layout/notification_template_base"
+    <include layout="@layout/notification_template_quantum_base"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a06a3fd..3746780 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -657,7 +657,9 @@
         <attr name="popupMenuStyle" format="reference" />
         <!-- Default StackView style. -->
         <attr name="stackViewStyle" format="reference" />
-        <!-- Default style for the FragmentBreadCrumbs widget. -->
+
+        <!-- Default style for the FragmentBreadCrumbs widget. This widget is deprecated
+             starting in API level 21 ({@link android.os.Build.VERSION_CODES#.L}). -->
         <attr name="fragmentBreadCrumbsStyle" format="reference" />
 
         <!-- NumberPicker style. -->
@@ -1670,6 +1672,7 @@
         <enum name="KEYCODE_MEDIA_AUDIO_TRACK" value="222" />
         <enum name="KEYCODE_MEDIA_SLEEP" value="223" />
         <enum name="KEYCODE_MEDIA_WAKEUP" value="224" />
+        <enum name="KEYCODE_PAIRING" value="225" />
     </attr>
 
     <!-- ***************************************************************** -->
@@ -1775,6 +1778,35 @@
              finishes. Corresponds to
              {@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. -->
         <attr name="windowAllowExitTransitionOverlap"/>
+
+        <!-- Flag indicating whether this Window is responsible for drawing the background for the
+             system bars. If true and the window is not floating, the system bars are drawn with a
+             transparent background and the corresponding areas in this window are filled with the
+             colors specified in {@link android.R.attr#statusBarColor} and
+             {@link android.R.attr#navigationBarColor}. Corresponds to
+             {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS}. -->
+        <attr name="windowDrawsSystemBarBackgrounds" format="boolean" />
+
+        <!-- The color for the status bar. If the color is not opaque, consider setting
+             {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
+             {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}.
+             For this to take effect, the window must be drawing the system bar backgrounds with
+             {@link android.R.attr#windowDrawsSystemBarBackgrounds} and the status bar must not
+             have been requested to be translucent with
+             {@link android.R.attr#windowTranslucentStatus}.
+             Corresponds to {@link android.view.Window#setStatusBarColor(int)}. -->
+        <attr name="statusBarColor" format="color" />
+
+        <!-- The color for the navigation bar. If the color is not opaque, consider setting
+             {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_STABLE} and
+             {@link android.view.View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
+             For this to take effect, the window must be drawing the system bar backgrounds with
+             {@link android.R.attr#windowDrawsSystemBarBackgrounds} and the navigation bar must not
+             have been requested to be translucent with
+             {@link android.R.attr#windowTranslucentNavigation}.
+             Corresponds to {@link android.view.Window#setNavigationBarColor(int)}. -->
+        <attr name="navigationBarColor" format="color" />
+
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -6084,13 +6116,13 @@
         <attr name="settingsActivity" />
     </declare-styleable>
 
-    <!-- Use <code>trust_agent</code> as the root tag of the XML resource that
+    <!-- Use <code>trust-agent</code> as the root tag of the XML resource that
          describes an {@link android.service.trust.TrustAgentService}, which is
          referenced from its {@link android.service.trust.TrustAgentService#TRUST_AGENT_META_DATA}
          meta-data entry.  Described here are the attributes that can be included in that tag. -->
     <declare-styleable name="TrustAgent">
         <!-- Component name of an activity that allows the user to modify
-             the settings for this TrustAgent. -->
+             the settings for this trust agent. -->
         <attr name="settingsActivity" />
     </declare-styleable>
 
@@ -6312,8 +6344,9 @@
     <!-- Use <code>voice-interaction-service</code> as the root tag of the XML resource that
          describes a {@link android.service.voice.VoiceInteractionService}, which is referenced from
          its {@link android.service.voice.VoiceInteractionService#SERVICE_META_DATA} meta-data entry.
-         Described here are the attributes that can be included in that tag. -->
+         Described here are the attributes that can be included in that tag. @hide -->
     <declare-styleable name="VoiceInteractionService">
+        <!-- @hide -->
         <attr name="sessionService" format="string" />
         <attr name="settingsActivity" />
     </declare-styleable>
@@ -6626,6 +6659,10 @@
         <attr name="titleMarginEnd" format="dimension" />
         <attr name="titleMarginTop" format="dimension" />
         <attr name="titleMarginBottom" format="dimension" />
+        <attr name="contentInsetStart" format="dimension" />
+        <attr name="contentInsetEnd" format="dimension" />
+        <attr name="contentInsetLeft" format="dimension" />
+        <attr name="contentInsetRight" format="dimension" />
     </declare-styleable>
 
     <declare-styleable name="Toolbar_LayoutParams">
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 69b11cd..52b021f 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -227,9 +227,9 @@
     <dimen name="action_bar_stacked_tab_max_width">180dp</dimen>
 
     <!-- Size of notification text (see TextAppearance.StatusBar.EventContent) -->
-    <dimen name="notification_text_size">14dp</dimen>
+    <dimen name="notification_text_size">13dp</dimen>
     <!-- Size of notification text titles (see TextAppearance.StatusBar.EventContent.Title) -->
-    <dimen name="notification_title_text_size">18dp</dimen>
+    <dimen name="notification_title_text_size">16dp</dimen>
     <!-- Size of smaller notification text (see TextAppearance.StatusBar.EventContent.Line2, Info, Time) -->
     <dimen name="notification_subtext_size">12dp</dimen>
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index de3a8d0..44b25f2b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2104,7 +2104,6 @@
 
   <public-padding type="attr" name="l_resource_pad" end="0x1010410" />
 
-  <public type="attr" name="fragmentBreadCrumbsStyle" />
   <public type="attr" name="fastScrollStyle" />
   <public type="attr" name="windowContentTransitions" />
   <public type="attr" name="windowContentTransitionManager" />
@@ -2171,6 +2170,13 @@
   <public type="attr" name="targetViewName" />
   <public type="attr" name="excludeViewName" />
   <public type="attr" name="matchOrder" />
+  <public type="attr" name="windowDrawsSystemBarBackgrounds" />
+  <public type="attr" name="statusBarColor"/>
+  <public type="attr" name="navigationBarColor"/>
+  <public type="attr" name="contentInsetStart" />
+  <public type="attr" name="contentInsetEnd" />
+  <public type="attr" name="contentInsetLeft" />
+  <public type="attr" name="contentInsetRight" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
@@ -2188,20 +2194,16 @@
   <public type="style" name="Widget.StackView" />
 
   <public type="style" name="Widget.Holo.FastScroll" />
-  <public type="style" name="Widget.Holo.FragmentBreadCrumbs" />
   <public type="style" name="Widget.Holo.StackView" />
 
   <public type="style" name="Widget.Holo.Light.Button.Borderless" />
   <public type="style" name="Widget.Holo.Light.FastScroll" />
-  <public type="style" name="Widget.Holo.Light.FragmentBreadCrumbs" />
   <public type="style" name="Widget.Holo.Light.StackView" />
 
   <public type="style" name="Widget.DeviceDefault.FastScroll" />
-  <public type="style" name="Widget.DeviceDefault.FragmentBreadCrumbs" />
   <public type="style" name="Widget.DeviceDefault.StackView" />
 
   <public type="style" name="Widget.DeviceDefault.Light.FastScroll" />
-  <public type="style" name="Widget.DeviceDefault.Light.FragmentBreadCrumbs" />
   <public type="style" name="Widget.DeviceDefault.Light.StackView" />
 
   <public type="style" name="TextAppearance.Quantum" />
@@ -2306,7 +2308,6 @@
   <public type="style" name="Widget.Quantum.EditText" />
   <public type="style" name="Widget.Quantum.ExpandableListView" />
   <public type="style" name="Widget.Quantum.FastScroll" />
-  <public type="style" name="Widget.Quantum.FragmentBreadCrumbs" />
   <public type="style" name="Widget.Quantum.GridView" />
   <public type="style" name="Widget.Quantum.HorizontalScrollView" />
   <public type="style" name="Widget.Quantum.ImageButton" />
@@ -2366,7 +2367,6 @@
   <public type="style" name="Widget.Quantum.Light.EditText" />
   <public type="style" name="Widget.Quantum.Light.ExpandableListView" />
   <public type="style" name="Widget.Quantum.Light.FastScroll" />
-  <public type="style" name="Widget.Quantum.Light.FragmentBreadCrumbs" />
   <public type="style" name="Widget.Quantum.Light.GridView" />
   <public type="style" name="Widget.Quantum.Light.HorizontalScrollView" />
   <public type="style" name="Widget.Quantum.Light.ImageButton" />
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 891265f..fd57c5e 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -280,28 +280,28 @@
     <style name="TextAppearance.StatusBar.Quantum">
     </style>
     <style name="TextAppearance.StatusBar.Quantum.EventContent">
-        <item name="android:textColor">#888888</item>
+        <item name="android:textColor">#90000000</item>
         <item name="android:textSize">@dimen/notification_text_size</item>
     </style>
     <style name="TextAppearance.StatusBar.Quantum.EventContent.Title">
-        <item name="android:textColor">#000000</item>
-        <item name="android:fontFamily">sans-serif-light</item>
+        <item name="android:textColor">#DD000000</item>
         <item name="android:textSize">@dimen/notification_title_text_size</item>
-        <item name="android:textStyle">bold</item>
     </style>
     <style name="TextAppearance.StatusBar.Quantum.EventContent.Line2">
         <item name="android:textSize">@dimen/notification_subtext_size</item>
     </style>
     <style name="TextAppearance.StatusBar.Quantum.EventContent.Info">
         <item name="android:textSize">@dimen/notification_subtext_size</item>
-        <item name="android:textColor">#888888</item>
     </style>
     <style name="TextAppearance.StatusBar.Quantum.EventContent.Time">
         <item name="android:textSize">@dimen/notification_subtext_size</item>
-        <item name="android:textColor">#888888</item>
     </style>
     <style name="TextAppearance.StatusBar.Quantum.EventContent.Emphasis">
-        <item name="android:textColor">#555555</item>
+        <item name="android:textColor">#66000000</item>
+    </style>
+
+    <style name="Widget.StatusBar.Quantum.ProgressBar"
+           parent="Widget.Quantum.Light.ProgressBar.Horizontal">
     </style>
 
     <style name="TextAppearance.Small.CalendarViewWeekDayView">
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 60e06ce..609a0f3 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -91,7 +91,8 @@
     <style name="Widget.DeviceDefault.CompoundButton.Switch" parent="Widget.Quantum.CompoundButton.Switch"/>
     <style name="Widget.DeviceDefault.ExpandableListView.White" parent="Widget.Quantum.ExpandableListView.White"/>
     <style name="Widget.DeviceDefault.FastScroll" parent="Widget.Quantum.FastScroll"/>
-    <style name="Widget.DeviceDefault.FragmentBreadCrumbs" parent="Widget.Quantum.FragmentBreadCrumbs"/>
+    <!-- The FragmentBreadCrumbs widget is deprecated starting in API level 21 ({@link android.os.Build.VERSION_CODES#.L}). -->
+    <style name="Widget.DeviceDefault.FragmentBreadCrumbs" parent="Widget.Holo.FragmentBreadCrumbs"/>
     <style name="Widget.DeviceDefault.Gallery" parent="Widget.Quantum.Gallery"/>
     <style name="Widget.DeviceDefault.GestureOverlayView" parent="Widget.Quantum.GestureOverlayView"/>
     <style name="Widget.DeviceDefault.ImageWell" parent="Widget.Quantum.ImageWell"/>
@@ -130,7 +131,8 @@
     <style name="Widget.DeviceDefault.Light.EditText" parent="Widget.Quantum.Light.EditText"/>
     <style name="Widget.DeviceDefault.Light.ExpandableListView" parent="Widget.Quantum.Light.ExpandableListView"/>
     <style name="Widget.DeviceDefault.Light.FastScroll" parent="Widget.Quantum.Light.FastScroll"/>
-    <style name="Widget.DeviceDefault.Light.FragmentBreadCrumbs" parent="Widget.Quantum.Light.FragmentBreadCrumbs"/>
+    <!-- The FragmentBreadCrumbs widget is deprecated starting in API level 21 ({@link android.os.Build.VERSION_CODES#.L}). -->
+    <style name="Widget.DeviceDefault.Light.FragmentBreadCrumbs" parent="Widget.Holo.Light.FragmentBreadCrumbs"/>
     <style name="Widget.DeviceDefault.Light.GridView" parent="Widget.Quantum.Light.GridView"/>
     <style name="Widget.DeviceDefault.Light.ImageButton" parent="Widget.Quantum.Light.ImageButton"/>
     <style name="Widget.DeviceDefault.Light.ListView" parent="Widget.Quantum.Light.ListView"/>
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index e693673..d04bddf 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -427,7 +427,10 @@
         <item name="paddingEnd">8dp</item>
     </style>
 
-    <style name="Widget.Quantum.CheckedTextView" parent="Widget.CheckedTextView"/>
+    <style name="Widget.Quantum.CheckedTextView" parent="Widget.CheckedTextView">
+        <item name="drawablePadding">4dip</item>
+    </style>
+
     <style name="Widget.Quantum.TextSelectHandle" parent="Widget.TextSelectHandle"/>
     <style name="Widget.Quantum.TextSuggestionsPopupWindow" parent="Widget.TextSuggestionsPopupWindow"/>
     <style name="Widget.Quantum.AbsListView" parent="Widget.AbsListView"/>
@@ -441,10 +444,12 @@
 
     <style name="Widget.Quantum.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox">
         <item name="background">?attr/selectableItemBackground</item>
+        <item name="drawablePadding">4dip</item>
     </style>
 
     <style name="Widget.Quantum.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton">
         <item name="background">?attr/selectableItemBackground</item>
+        <item name="drawablePadding">4dip</item>
     </style>
 
     <style name="Widget.Quantum.CompoundButton.Star" parent="Widget.CompoundButton.Star">
@@ -474,7 +479,6 @@
     </style>
 
     <style name="Widget.Quantum.ExpandableListView.White"/>
-    <style name="Widget.Quantum.FragmentBreadCrumbs" parent="Widget.FragmentBreadCrumbs"/>
     <style name="Widget.Quantum.Gallery" parent="Widget.Gallery"/>
     <style name="Widget.Quantum.GestureOverlayView" parent="Widget.GestureOverlayView"/>
     <style name="Widget.Quantum.GridView" parent="Widget.GridView"/>
@@ -820,7 +824,6 @@
     <style name="Widget.Quantum.Light.EditText" parent="Widget.Quantum.EditText"/>
     <style name="Widget.Quantum.Light.ExpandableListView" parent="Widget.Quantum.ExpandableListView"/>
     <style name="Widget.Quantum.Light.ExpandableListView.White" parent="Widget.Quantum.ExpandableListView.White"/>
-    <style name="Widget.Quantum.Light.FragmentBreadCrumbs" parent="Widget.Quantum.FragmentBreadCrumbs"/>
     <style name="Widget.Quantum.Light.Gallery" parent="Widget.Quantum.Gallery"/>
     <style name="Widget.Quantum.Light.GestureOverlayView" parent="Widget.Quantum.GestureOverlayView"/>
     <style name="Widget.Quantum.Light.GridView" parent="Widget.Quantum.GridView"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 84c9023..2f0ac49 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1209,16 +1209,7 @@
   <java-symbol type="layout" name="zoom_container" />
   <java-symbol type="layout" name="zoom_controls" />
   <java-symbol type="layout" name="zoom_magnify" />
-  <java-symbol type="layout" name="notification_action" />
-  <java-symbol type="layout" name="notification_action_tombstone" />
   <java-symbol type="layout" name="notification_intruder_content" />
-  <java-symbol type="layout" name="notification_template_base" />
-  <java-symbol type="layout" name="notification_template_big_base" />
-  <java-symbol type="layout" name="notification_template_big_picture" />
-  <java-symbol type="layout" name="notification_template_big_text" />
-  <java-symbol type="layout" name="notification_template_part_time" />
-  <java-symbol type="layout" name="notification_template_part_chronometer" />
-  <java-symbol type="layout" name="notification_template_inbox" />
   <java-symbol type="layout" name="sms_short_code_confirmation_dialog" />
   <java-symbol type="layout" name="action_bar_up_container" />
   <java-symbol type="layout" name="app_not_authorized" />
@@ -1667,8 +1658,10 @@
   <java-symbol type="layout" name="notification_template_quantum_big_picture" />
   <java-symbol type="layout" name="notification_template_quantum_big_text" />
   <java-symbol type="layout" name="notification_template_quantum_inbox" />
+  <java-symbol type="layout" name="notification_template_icon_group" />
   <java-symbol type="color" name="notification_action_legacy_color_filter" />
   <java-symbol type="color" name="notification_icon_bg_color" />
+  <java-symbol type="drawable" name="notification_icon_legacy_bg" />
   <java-symbol type="drawable" name="notification_icon_legacy_bg_inset" />
   <java-symbol type="drawable" name="notification_quantum_bg_dim" />
   <java-symbol type="drawable" name="notification_quantum_bg" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 1d9bbae..743ad61 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -189,6 +189,9 @@
         <item name="windowCloseOnTouchOutside">false</item>
         <item name="windowTranslucentStatus">false</item>
         <item name="windowTranslucentNavigation">false</item>
+        <item name="windowDrawsSystemBarBackgrounds">false</item>
+        <item name="statusBarColor">@android:color/black</item>
+        <item name="navigationBarColor">@android:color/black</item>
 
         <!-- Define these here; ContextThemeWrappers around themes that define them should
              always clear these values. -->
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index f45fbac..e7cf9da 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -161,6 +161,9 @@
         <item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
         <item name="windowActionBar">true</item>
         <item name="windowActionModeOverlay">false</item>
+        <item name="windowDrawsSystemBarBackgrounds">true</item>
+        <item name="statusBarColor">?attr/colorPrimaryDark</item>
+        <item name="navigationBarColor">?attr/colorPrimaryDark</item>
 
         <!-- Dialog attributes -->
         <item name="dialogTheme">@style/Theme.Quantum.Dialog</item>
@@ -266,7 +269,6 @@
         <item name="popupMenuStyle">@style/Widget.Quantum.PopupMenu</item>
         <item name="stackViewStyle">@style/Widget.Quantum.StackView</item>
         <item name="activityChooserViewStyle">@style/Widget.Quantum.ActivityChooserView</item>
-        <item name="fragmentBreadCrumbsStyle">@style/Widget.Quantum.FragmentBreadCrumbs</item>
 
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@style/Preference.Quantum.PreferenceScreen</item>
@@ -501,6 +503,9 @@
         <item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
         <item name="windowActionBar">true</item>
         <item name="windowActionModeOverlay">false</item>
+        <item name="windowDrawsSystemBarBackgrounds">true</item>
+        <item name="statusBarColor">?attr/colorPrimaryDark</item>
+        <item name="navigationBarColor">?attr/colorPrimaryDark</item>
 
         <!-- Dialog attributes -->
         <item name="dialogTheme">@style/Theme.Quantum.Light.Dialog</item>
@@ -606,7 +611,6 @@
         <item name="popupMenuStyle">@style/Widget.Quantum.Light.PopupMenu</item>
         <item name="stackViewStyle">@style/Widget.Quantum.Light.StackView</item>
         <item name="activityChooserViewStyle">@style/Widget.Quantum.Light.ActivityChooserView</item>
-        <item name="fragmentBreadCrumbsStyle">@style/Widget.Quantum.Light.FragmentBreadCrumbs</item>
 
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@style/Preference.Quantum.PreferenceScreen</item>
diff --git a/core/tests/coretests/src/android/view/VelocityTest.java b/core/tests/coretests/src/android/view/VelocityTest.java
index fb28e1e..12abf3e 100644
--- a/core/tests/coretests/src/android/view/VelocityTest.java
+++ b/core/tests/coretests/src/android/view/VelocityTest.java
@@ -14,14 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.frameworktest.view;
+package android.view;
 
 import junit.framework.Assert;
 
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -30,7 +28,7 @@
 /**
  * Exercises {@link android.view.VelocityTracker} to compute correct velocity.<br>
  * To launch this test, use :<br>
- * <code>./development/testrunner/runtest.py framework -c com.android.frameworktest.view.VelocityTest</code>
+ * <code>./development/testrunner/runtest.py framework -c android.view.VelocityTest</code>
  */
 public class VelocityTest extends InstrumentationTestCase {
 
diff --git a/graphics/java/android/graphics/LayerRasterizer.java b/graphics/java/android/graphics/LayerRasterizer.java
index 5b356089..e7a24a4 100644
--- a/graphics/java/android/graphics/LayerRasterizer.java
+++ b/graphics/java/android/graphics/LayerRasterizer.java
@@ -16,11 +16,12 @@
 
 package android.graphics;
 
+@Deprecated
 public class LayerRasterizer extends Rasterizer {
     public LayerRasterizer() {
         native_instance = nativeConstructor();
     }
-    
+
     /** Add a new layer (above any previous layers) to the rasterizer.
         The layer will extract those fields that affect the mask from
         the specified paint, but will not retain a reference to the paint
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index 66bf75c..b4e6bab 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -245,6 +245,16 @@
     }
 
     /**
+     * Gets whether this matrix is affine. An affine matrix preserves
+     * straight lines and has no perspective.
+     *
+     * @return Whether the matrix is affine.
+     */
+    public boolean isAffine() {
+        return native_isAffine(native_instance);
+    }
+
+    /**
      * Returns true if will map a rectangle to another rectangle. This can be
      * true if the matrix is identity, scale-only, or rotates a multiple of 90
      * degrees.
@@ -828,6 +838,7 @@
 
     private static native long native_create(long native_src_or_zero);
     private static native boolean native_isIdentity(long native_object);
+    private static native boolean native_isAffine(long native_object);
     private static native boolean native_rectStaysRect(long native_object);
     private static native void native_reset(long native_object);
     private static native void native_set(long native_object,
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index b5c0801..c6ba75c 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -53,8 +53,7 @@
         set(src);
     }
 
-    /** @hide */
-    public void markInvalid() {
+    public void reset() {
         mRadius = 0;
         mRect = null;
         mPath = null;
@@ -74,27 +73,21 @@
      *
      * @param src Source outline to copy from.
      */
-    public void set(@Nullable Outline src) {
-        if (src == null) {
-            mRadius = 0;
+    public void set(@NonNull Outline src) {
+        if (src.mPath != null) {
+            if (mPath == null) {
+                mPath = new Path();
+            }
+            mPath.set(src.mPath);
             mRect = null;
-            mPath = null;
-        } else {
-            if (src.mPath != null) {
-                if (mPath == null) {
-                    mPath = new Path();
-                }
-                mPath.set(src.mPath);
-                mRect = null;
-            }
-            if (src.mRect != null) {
-                if (mRect == null) {
-                    mRect = new Rect();
-                }
-                mRect.set(src.mRect);
-            }
-            mRadius = src.mRadius;
         }
+        if (src.mRect != null) {
+            if (mRect == null) {
+                mRect = new Rect();
+            }
+            mRect.set(src.mRect);
+        }
+        mRadius = src.mRadius;
     }
 
     /**
@@ -134,6 +127,11 @@
      * Sets the outline to the oval defined by input rect.
      */
     public void setOval(int left, int top, int right, int bottom) {
+        if ((bottom - top) == (right - left)) {
+            // represent circle as round rect, for efficiency, and to enable clipping
+            setRoundRect(left, top, right, bottom, (bottom - top) / 2.0f);
+            return;
+        }
         mRect = null;
         if (mPath == null) mPath = new Path();
         mPath.reset();
@@ -160,4 +158,16 @@
         mRadius = -1.0f;
         mPath.set(convexPath);
     }
+
+    /**
+     * Returns whether the outline can be used to clip a View.
+     *
+     * Currently, only outlines that can be represented as a rectangle, circle, or round rect
+     * support clipping.
+     *
+     * @see {@link View#setClipToOutline(boolean)}
+     */
+    public boolean canClip() {
+        return mRect != null;
+    }
 }
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index bdef404..92cfd6b 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1064,14 +1064,17 @@
         mNativeTypeface = typefaceNative;
         return typeface;
     }
-    
+
     /**
      * Get the paint's rasterizer (or null).
      * <p />
      * The raster controls/modifies how paths/text are turned into alpha masks.
      *
      * @return         the paint's rasterizer (or null)
+     *
+     *  @deprecated Rasterizer is not supported by either the HW or PDF backends.
      */
+    @Deprecated
     public Rasterizer getRasterizer() {
         return mRasterizer;
     }
@@ -1085,7 +1088,10 @@
      * @param rasterizer May be null. The new rasterizer to be installed in
      *                   the paint.
      * @return           rasterizer
+     *
+     *  @deprecated Rasterizer is not supported by either the HW or PDF backends.
      */
+    @Deprecated
     public Rasterizer setRasterizer(Rasterizer rasterizer) {
         long rasterizerNative = 0;
         if (rasterizer != null) {
@@ -1095,7 +1101,7 @@
         mRasterizer = rasterizer;
         return rasterizer;
     }
-    
+
     /**
      * This draws a shadow layer below the main layer, with the specified
      * offset and color, and blur radius. If radius is 0, then the shadow
diff --git a/graphics/java/android/graphics/Rasterizer.java b/graphics/java/android/graphics/Rasterizer.java
index 817814c..c351d94 100644
--- a/graphics/java/android/graphics/Rasterizer.java
+++ b/graphics/java/android/graphics/Rasterizer.java
@@ -21,6 +21,7 @@
 
 package android.graphics;
 
+@Deprecated
 public class Rasterizer {
 
     protected void finalize() throws Throwable {
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 60b4615..6755f3e 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -67,16 +67,23 @@
  * @attr ref android.R.styleable#BitmapDrawable_tileMode
  */
 public class BitmapDrawable extends Drawable {
-
     private static final int DEFAULT_PAINT_FLAGS =
             Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
-    private BitmapState mBitmapState;
-    private Bitmap mBitmap;
-    private PorterDuffColorFilter mTintFilter;
-    private int mTargetDensity;
+
+    // Constants for {@link android.R.styleable#BitmapDrawable_tileMode}.
+    private static final int TILE_MODE_UNDEFINED = -2;
+    private static final int TILE_MODE_DISABLED = -1;
+    private static final int TILE_MODE_CLAMP = 0;
+    private static final int TILE_MODE_REPEAT = 1;
+    private static final int TILE_MODE_MIRROR = 2;
 
     private final Rect mDstRect = new Rect();   // Gravity.apply() sets this
 
+    private BitmapState mBitmapState;
+    private PorterDuffColorFilter mTintFilter;
+
+    private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+
     private boolean mApplyGravity;
     private boolean mMutated;
 
@@ -100,11 +107,12 @@
     /**
      * Create an empty drawable, setting initial target density based on
      * the display metrics of the resources.
+     *
      * @deprecated Use {@link #BitmapDrawable(android.content.res.Resources, android.graphics.Bitmap)}
      * instead to specify a bitmap to draw with.
      */
+    @SuppressWarnings("unused")
     @Deprecated
-    @SuppressWarnings({"UnusedParameters"})
     public BitmapDrawable(Resources res) {
         mBitmapState = new BitmapState((Bitmap) null);
         mBitmapState.mTargetDensity = mTargetDensity;
@@ -137,7 +145,7 @@
     @Deprecated
     public BitmapDrawable(String filepath) {
         this(new BitmapState(BitmapFactory.decodeFile(filepath)), null, null);
-        if (mBitmap == null) {
+        if (mBitmapState.mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
         }
     }
@@ -145,11 +153,11 @@
     /**
      * Create a drawable by opening a given file path and decoding the bitmap.
      */
-    @SuppressWarnings({"UnusedParameters"})
+    @SuppressWarnings("unused")
     public BitmapDrawable(Resources res, String filepath) {
         this(new BitmapState(BitmapFactory.decodeFile(filepath)), null, null);
         mBitmapState.mTargetDensity = mTargetDensity;
-        if (mBitmap == null) {
+        if (mBitmapState.mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
         }
     }
@@ -162,7 +170,7 @@
     @Deprecated
     public BitmapDrawable(java.io.InputStream is) {
         this(new BitmapState(BitmapFactory.decodeStream(is)), null, null);
-        if (mBitmap == null) {
+        if (mBitmapState.mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
         }
     }
@@ -170,11 +178,11 @@
     /**
      * Create a drawable by decoding a bitmap from the given input stream.
      */
-    @SuppressWarnings({"UnusedParameters"})
+    @SuppressWarnings("unused")
     public BitmapDrawable(Resources res, java.io.InputStream is) {
         this(new BitmapState(BitmapFactory.decodeStream(is)), null, null);
         mBitmapState.mTargetDensity = mTargetDensity;
-        if (mBitmap == null) {
+        if (mBitmapState.mBitmap == null) {
             android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
         }
     }
@@ -190,22 +198,23 @@
      * Returns the bitmap used by this drawable to render. May be null.
      */
     public final Bitmap getBitmap() {
-        return mBitmap;
+        return mBitmapState.mBitmap;
     }
 
     private void computeBitmapSize() {
-        mBitmapWidth = mBitmap.getScaledWidth(mTargetDensity);
-        mBitmapHeight = mBitmap.getScaledHeight(mTargetDensity);
+        final Bitmap bitmap = mBitmapState.mBitmap;
+        if (bitmap != null) {
+            mBitmapWidth = bitmap.getScaledWidth(mTargetDensity);
+            mBitmapHeight = bitmap.getScaledHeight(mTargetDensity);
+        } else {
+            mBitmapWidth = mBitmapHeight = -1;
+        }
     }
 
     private void setBitmap(Bitmap bitmap) {
-        if (bitmap != mBitmap) {
-            mBitmap = bitmap;
-            if (bitmap != null) {
-                computeBitmapSize();
-            } else {
-                mBitmapWidth = mBitmapHeight = -1;
-            }
+        if (mBitmapState.mBitmap != bitmap) {
+            mBitmapState.mBitmap = bitmap;
+            computeBitmapSize();
             invalidateSelf();
         }
     }
@@ -247,7 +256,7 @@
     public void setTargetDensity(int density) {
         if (mTargetDensity != density) {
             mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
-            if (mBitmap != null) {
+            if (mBitmapState.mBitmap != null) {
                 computeBitmapSize();
             }
             invalidateSelf();
@@ -343,8 +352,9 @@
     /**
      * Indicates the repeat behavior of this drawable on the X axis.
      *
-     * @return {@link Shader.TileMode#CLAMP} if the bitmap does not repeat,
-     *         {@link Shader.TileMode#REPEAT} or {@link Shader.TileMode#MIRROR} otherwise.
+     * @return {@link android.graphics.Shader.TileMode#CLAMP} if the bitmap does not repeat,
+     *         {@link android.graphics.Shader.TileMode#REPEAT} or
+     *         {@link android.graphics.Shader.TileMode#MIRROR} otherwise.
      */
     public Shader.TileMode getTileModeX() {
         return mBitmapState.mTileModeX;
@@ -353,8 +363,9 @@
     /**
      * Indicates the repeat behavior of this drawable on the Y axis.
      *
-     * @return {@link Shader.TileMode#CLAMP} if the bitmap does not repeat,
-     *         {@link Shader.TileMode#REPEAT} or {@link Shader.TileMode#MIRROR} otherwise.
+     * @return {@link android.graphics.Shader.TileMode#CLAMP} if the bitmap does not repeat,
+     *         {@link android.graphics.Shader.TileMode#REPEAT} or
+     *         {@link android.graphics.Shader.TileMode#MIRROR} otherwise.
      */
     public Shader.TileMode getTileModeY() {
         return mBitmapState.mTileModeY;
@@ -362,9 +373,9 @@
 
     /**
      * Sets the repeat behavior of this drawable on the X axis. By default, the drawable
-     * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
-     * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
-     * is smaller than this drawable.
+     * does not repeat its bitmap. Using {@link android.graphics.Shader.TileMode#REPEAT} or
+     * {@link android.graphics.Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled)
+     * if the bitmap is smaller than this drawable.
      *
      * @param mode The repeat mode for this drawable.
      *
@@ -377,9 +388,9 @@
 
     /**
      * Sets the repeat behavior of this drawable on the Y axis. By default, the drawable
-     * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
-     * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
-     * is smaller than this drawable.
+     * does not repeat its bitmap. Using {@link android.graphics.Shader.TileMode#REPEAT} or
+     * {@link android.graphics.Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled)
+     * if the bitmap is smaller than this drawable.
      *
      * @param mode The repeat mode for this drawable.
      *
@@ -392,9 +403,9 @@
 
     /**
      * Sets the repeat behavior of this drawable on both axis. By default, the drawable
-     * does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
-     * {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
-     * is smaller than this drawable.
+     * does not repeat its bitmap. Using {@link android.graphics.Shader.TileMode#REPEAT} or
+     * {@link android.graphics.Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled)
+     * if the bitmap is smaller than this drawable.
      *
      * @param xmode The X repeat mode for this drawable.
      * @param ymode The Y repeat mode for this drawable.
@@ -462,7 +473,7 @@
 
     @Override
     public void draw(Canvas canvas) {
-        final Bitmap bitmap = mBitmap;
+        final Bitmap bitmap = mBitmapState.mBitmap;
         if (bitmap == null) {
             return;
         }
@@ -589,7 +600,7 @@
     public void setTint(ColorStateList tint) {
         if (mBitmapState.mTint != tint) {
             mBitmapState.mTint = tint;
-            updateTintFilter();
+            computeTintFilter();
             invalidateSelf();
         }
     }
@@ -612,7 +623,7 @@
     public void setTintMode(Mode tintMode) {
         if (mBitmapState.mTintMode != tintMode) {
             mBitmapState.mTintMode = tintMode;
-            updateTintFilter();
+            computeTintFilter();
             invalidateSelf();
         }
     }
@@ -624,18 +635,15 @@
         return mBitmapState.mTintMode;
     }
 
-    /**
-     * Ensures the tint filter is consistent with the current tint color and
-     * mode.
-     */
-    private void updateTintFilter() {
-        final ColorStateList tint = mBitmapState.mTint;
-        final Mode tintMode = mBitmapState.mTintMode;
-        if (tint != null && tintMode != null) {
-            if (mTintFilter == null) {
-                mTintFilter = new PorterDuffColorFilter(0, tintMode);
+    private void computeTintFilter() {
+        final BitmapState state = mBitmapState;
+        if (state.mTint != null && state.mTintMode != null) {
+            final int color = state.mTint.getColorForState(getState(), 0);
+            if (mTintFilter != null) {
+                mTintFilter.setColor(color);
+                mTintFilter.setMode(state.mTintMode);
             } else {
-                mTintFilter.setMode(tintMode);
+                mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
             }
         } else {
             mTintFilter = null;
@@ -693,16 +701,15 @@
             throws XmlPullParserException, IOException {
         super.inflate(r, parser, attrs, theme);
 
-        final TypedArray a = obtainAttributes(
-                r, theme, attrs, R.styleable.BitmapDrawable);
-        inflateStateFromTypedArray(a);
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.BitmapDrawable);
+        updateStateFromTypedArray(a);
         a.recycle();
     }
 
     /**
-     * Initializes the constant state from the values in the typed array.
+     * Updates the constant state from the values in the typed array.
      */
-    private void inflateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+    private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
         final Resources r = a.getResources();
         final BitmapState state = mBitmapState;
 
@@ -710,86 +717,52 @@
         final int[] themeAttrs = a.extractThemeAttrs();
         state.mThemeAttrs = themeAttrs;
 
-        if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_src] == 0) {
-            final int id = a.getResourceId(R.styleable.BitmapDrawable_src, 0);
-            if (id == 0) {
-                throw new XmlPullParserException(a.getPositionDescription() +
-                        ": <bitmap> requires a valid src attribute");
-            }
-
-            final Bitmap bitmap = BitmapFactory.decodeResource(r, id);
+        final int srcResId = a.getResourceId(R.styleable.BitmapDrawable_src, 0);
+        if (srcResId != 0) {
+            final Bitmap bitmap = BitmapFactory.decodeResource(r, srcResId);
             if (bitmap == null) {
                 throw new XmlPullParserException(a.getPositionDescription() +
                         ": <bitmap> requires a valid src attribute");
             }
+
             state.mBitmap = bitmap;
-            setBitmap(bitmap);
         }
 
-        setTargetDensity(r.getDisplayMetrics());
+        state.mTargetDensity = r.getDisplayMetrics().densityDpi;
 
-        if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_mipMap] == 0) {
-            final boolean defMipMap = state.mBitmap != null ? state.mBitmap.hasMipMap() : false;
-            final boolean mipMap = a.getBoolean(
-                    R.styleable.BitmapDrawable_mipMap, defMipMap);
-            setMipMap(mipMap);
+        final boolean defMipMap = state.mBitmap != null ? state.mBitmap.hasMipMap() : false;
+        setMipMap(a.getBoolean(R.styleable.BitmapDrawable_mipMap, defMipMap));
+
+        state.mAutoMirrored = a.getBoolean(
+                R.styleable.BitmapDrawable_autoMirrored, state.mAutoMirrored);
+        state.mBaseAlpha = a.getFloat(R.styleable.BitmapDrawable_alpha, state.mBaseAlpha);
+
+        final int tintMode = a.getInt(R.styleable.BitmapDrawable_tintMode, -1);
+        if (tintMode != -1) {
+            state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
         }
 
-        if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_autoMirrored] == 0) {
-            final boolean autoMirrored = a.getBoolean(
-                    R.styleable.BitmapDrawable_autoMirrored, false);
-            setAutoMirrored(autoMirrored);
-        }
-
-        if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_tintMode] == 0) {
-            final int tintModeValue = a.getInt(
-                    R.styleable.BitmapDrawable_tintMode, -1);
-            state.mTintMode = Drawable.parseTintMode(tintModeValue, Mode.SRC_IN);
-        }
-
-        if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_tint] == 0) {
-            state.mTint = a.getColorStateList(R.styleable.BitmapDrawable_tint);
-            if (state.mTint != null) {
-                final int color = state.mTint.getColorForState(getState(), 0);
-                mTintFilter = new PorterDuffColorFilter(color, mBitmapState.mTintMode);
-            }
+        final ColorStateList tint = a.getColorStateList(R.styleable.BitmapDrawable_tint);
+        if (tint != null) {
+            state.mTint = tint;
         }
 
         final Paint paint = mBitmapState.mPaint;
+        paint.setAntiAlias(a.getBoolean(
+                R.styleable.BitmapDrawable_antialias, paint.isAntiAlias()));
+        paint.setFilterBitmap(a.getBoolean(
+                R.styleable.BitmapDrawable_filter, paint.isFilterBitmap()));
+        paint.setDither(a.getBoolean(R.styleable.BitmapDrawable_dither, paint.isDither()));
 
-        if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_antialias] == 0) {
-            final boolean antiAlias = a.getBoolean(
-                    R.styleable.BitmapDrawable_antialias, paint.isAntiAlias());
-            paint.setAntiAlias(antiAlias);
-        }
+        setGravity(a.getInt(R.styleable.BitmapDrawable_gravity, state.mGravity));
 
-        if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_filter] == 0) {
-            final boolean filter = a.getBoolean(
-                    R.styleable.BitmapDrawable_filter, paint.isFilterBitmap());
-            paint.setFilterBitmap(filter);
-        }
-
-        if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_dither] == 0) {
-            final boolean dither = a.getBoolean(
-                    R.styleable.BitmapDrawable_dither, paint.isDither());
-            paint.setDither(dither);
-        }
-
-        if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_alpha] == 0) {
-            state.mBaseAlpha = a.getFloat(R.styleable.BitmapDrawable_alpha, 1.0f);
-        }
-
-        if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_gravity] == 0) {
-            final int gravity = a.getInt(
-                    R.styleable.BitmapDrawable_gravity, Gravity.FILL);
-            setGravity(gravity);
-        }
-
-        if (themeAttrs == null || themeAttrs[R.styleable.BitmapDrawable_tileMode] == 0) {
-            final int tileMode = a.getInt(
-                    R.styleable.BitmapDrawable_tileMode, -1);
+        final int tileMode = a.getInt(R.styleable.BitmapDrawable_tileMode, TILE_MODE_UNDEFINED);
+        if (tileMode != TILE_MODE_UNDEFINED) {
             setTileModeInternal(tileMode);
         }
+
+        // Update local properties.
+        initializeWithState(state, r);
     }
 
     @Override
@@ -797,120 +770,32 @@
         super.applyTheme(t);
 
         final BitmapState state = mBitmapState;
-        if (state == null) {
-            throw new RuntimeException("Can't apply theme to <bitmap> with no constant state");
+        if (state == null || state.mThemeAttrs == null) {
+            return;
         }
 
-        final int[] themeAttrs = state.mThemeAttrs;
-        if (themeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(themeAttrs, R.styleable.BitmapDrawable, 0, 0);
+        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.BitmapDrawable);
+        try {
             updateStateFromTypedArray(a);
+        } catch (XmlPullParserException e) {
+            throw new RuntimeException(e);
+        } finally {
             a.recycle();
         }
     }
 
-    /**
-     * Updates the constant state from the values in the typed array.
-     */
-    private void updateStateFromTypedArray(TypedArray a) {
-        final Resources r = a.getResources();
-        final BitmapState state = mBitmapState;
-        final Paint paint = mBitmapState.mPaint;
-
-        if (a.hasValue(R.styleable.BitmapDrawable_antialias)) {
-            final boolean antiAlias = a.getBoolean(
-                    R.styleable.BitmapDrawable_antialias, paint.isAntiAlias());
-            paint.setAntiAlias(antiAlias);
-        }
-
-        if (a.hasValue(R.styleable.BitmapDrawable_filter)) {
-            final boolean filter = a.getBoolean(
-                    R.styleable.BitmapDrawable_filter, paint.isFilterBitmap());
-            paint.setFilterBitmap(filter);
-        }
-
-        if (a.hasValue(R.styleable.BitmapDrawable_dither)) {
-            final boolean dither = a.getBoolean(
-                    R.styleable.BitmapDrawable_dither, paint.isDither());
-            paint.setDither(dither);
-        }
-
-        if (a.hasValue(R.styleable.BitmapDrawable_alpha)) {
-            state.mBaseAlpha = a.getFloat(R.styleable.BitmapDrawable_alpha, state.mBaseAlpha);
-        }
-
-        if (a.hasValue(R.styleable.BitmapDrawable_gravity)) {
-            final int gravity = a.getInt(
-                    R.styleable.BitmapDrawable_gravity, Gravity.FILL);
-            setGravity(gravity);
-        }
-
-        if (a.hasValue(R.styleable.BitmapDrawable_tileMode)) {
-            final int tileMode = a.getInt(
-                    R.styleable.BitmapDrawable_tileMode, -1);
-            setTileModeInternal(tileMode);
-        }
-
-        if (a.hasValue(R.styleable.BitmapDrawable_src)) {
-            final int id = a.getResourceId(R.styleable.BitmapDrawable_src, 0);
-            if (id == 0) {
-                throw new RuntimeException(a.getPositionDescription() +
-                        ": <bitmap> requires a valid src attribute");
-            }
-
-            final Bitmap bitmap = BitmapFactory.decodeResource(r, id);
-            if (bitmap == null) {
-                throw new RuntimeException(a.getPositionDescription() +
-                        ": <bitmap> requires a valid src attribute");
-            }
-
-            setBitmap(bitmap);
-        }
-
-        setTargetDensity(r.getDisplayMetrics());
-
-        if (a.hasValue(R.styleable.BitmapDrawable_mipMap)) {
-            final boolean mipMap = a.getBoolean(
-                    R.styleable.BitmapDrawable_mipMap,
-                    state.mBitmap.hasMipMap());
-            setMipMap(mipMap);
-        }
-
-        if (a.hasValue(R.styleable.BitmapDrawable_autoMirrored)) {
-            final boolean autoMirrored = a.getBoolean(
-                    R.styleable.BitmapDrawable_autoMirrored, false);
-            setAutoMirrored(autoMirrored);
-        }
-
-        if (a.hasValue(R.styleable.BitmapDrawable_tintMode)) {
-            final int modeValue = a.getInt(
-                    R.styleable.BitmapDrawable_tintMode, -1);
-            state.mTintMode = Drawable.parseTintMode(modeValue, Mode.SRC_IN);
-        }
-
-        if (a.hasValue(R.styleable.BitmapDrawable_tint)) {
-            final ColorStateList tint = a.getColorStateList(
-                    R.styleable.BitmapDrawable_tint);
-            if (tint != null) {
-                state.mTint = tint;
-                final int color = tint.getColorForState(getState(), 0);
-                mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
-            }
-        }
-    }
-
     private void setTileModeInternal(final int tileMode) {
         switch (tileMode) {
-            case -1:
-                // Do nothing.
+            case TILE_MODE_DISABLED:
+                setTileModeXY(null, null);
                 break;
-            case 0:
+            case TILE_MODE_CLAMP:
                 setTileModeXY(Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
                 break;
-            case 1:
+            case TILE_MODE_REPEAT:
                 setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
                 break;
-            case 2:
+            case TILE_MODE_MIRROR:
                 setTileModeXY(Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
                 break;
         }
@@ -936,8 +821,9 @@
         if (mBitmapState.mGravity != Gravity.FILL) {
             return PixelFormat.TRANSLUCENT;
         }
-        Bitmap bm = mBitmap;
-        return (bm == null || bm.hasAlpha() || mBitmapState.mPaint.getAlpha() < 255) ?
+
+        final Bitmap bitmap = mBitmapState.mBitmap;
+        return (bitmap == null || bitmap.hasAlpha() || mBitmapState.mPaint.getAlpha() < 255) ?
                 PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE;
     }
 
@@ -948,22 +834,26 @@
     }
 
     final static class BitmapState extends ConstantState {
-        Bitmap mBitmap;
-        ColorStateList mTint;
+        final Paint mPaint;
+
+        // Values loaded during inflation.
+        int[] mThemeAttrs = null;
+        Bitmap mBitmap = null;
+        ColorStateList mTint = null;
         Mode mTintMode = Mode.SRC_IN;
-        int[] mThemeAttrs;
-        int mChangingConfigurations;
         int mGravity = Gravity.FILL;
         float mBaseAlpha = 1.0f;
-        Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS);
         Shader.TileMode mTileModeX = null;
         Shader.TileMode mTileModeY = null;
         int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+        boolean mAutoMirrored = false;
+
+        int mChangingConfigurations;
         boolean mRebuildShader;
-        boolean mAutoMirrored;
 
         BitmapState(Bitmap bitmap) {
             mBitmap = bitmap;
+            mPaint = new Paint(DEFAULT_PAINT_FLAGS);
         }
 
         BitmapState(BitmapState bitmapState) {
@@ -1013,6 +903,10 @@
         }
     }
 
+    /**
+     * The one constructor to rule them all. This is called by all public
+     * constructors to set the state and initialize local properties.
+     */
     private BitmapDrawable(BitmapState state, Resources res, Theme theme) {
         if (theme != null && state.canApplyTheme()) {
             mBitmapState = new BitmapState(state);
@@ -1034,11 +928,7 @@
             mTargetDensity = state.mTargetDensity;
         }
 
-        if (state.mTint != null) {
-            final int color = state.mTint.getColorForState(getState(), 0);
-            mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
-        }
-
-        setBitmap(state.mBitmap);
+        computeTintFilter();
+        computeBitmapSize();
     }
 }
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 8243b7c..df5ca33 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -199,7 +199,7 @@
 
         final int[] themeAttrs = state.mThemeAttrs;
         if (themeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(themeAttrs, R.styleable.ColorDrawable, 0, 0);
+            final TypedArray a = t.resolveAttributes(themeAttrs, R.styleable.ColorDrawable);
             updateStateFromTypedArray(a);
             a.recycle();
         }
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index dc06350..8fe1544 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -1053,7 +1053,7 @@
         final int[] themeAttrs = state.mThemeAttrs;
         if (themeAttrs != null) {
             final TypedArray a = t.resolveAttributes(
-                    themeAttrs, R.styleable.GradientDrawable, 0, 0);
+                    themeAttrs, R.styleable.GradientDrawable);
             updateStateFromTypedArray(a);
             a.recycle();
 
@@ -1123,37 +1123,37 @@
         TypedArray a;
 
         if (state.mAttrSize != null) {
-            a = t.resolveAttributes(state.mAttrSize, R.styleable.GradientDrawableSize, 0, 0);
+            a = t.resolveAttributes(state.mAttrSize, R.styleable.GradientDrawableSize);
             // TODO: updateGradientDrawableSize(a);
             a.recycle();
         }
 
         if (state.mAttrGradient != null) {
-            a = t.resolveAttributes(state.mAttrGradient, R.styleable.GradientDrawableGradient, 0, 0);
+            a = t.resolveAttributes(state.mAttrGradient, R.styleable.GradientDrawableGradient);
             // TODO: updateGradientDrawableGradient(a);
             a.recycle();
         }
 
         if (state.mAttrSolid != null) {
-            a = t.resolveAttributes(state.mAttrSolid, R.styleable.GradientDrawableSolid, 0, 0);
+            a = t.resolveAttributes(state.mAttrSolid, R.styleable.GradientDrawableSolid);
             // TODO: updateGradientDrawableSolid(a);
             a.recycle();
         }
 
         if (state.mAttrStroke != null) {
-            a = t.resolveAttributes(state.mAttrStroke, R.styleable.GradientDrawableStroke, 0, 0);
+            a = t.resolveAttributes(state.mAttrStroke, R.styleable.GradientDrawableStroke);
             // TODO: updateGradientDrawableStroke(a);
             a.recycle();
         }
 
         if (state.mAttrCorners != null) {
-            a = t.resolveAttributes(state.mAttrCorners, R.styleable.DrawableCorners, 0, 0);
+            a = t.resolveAttributes(state.mAttrCorners, R.styleable.DrawableCorners);
             // TODO: updateDrawableCorners(a);
             a.recycle();
         }
 
         if (state.mAttrPadding != null) {
-            a = t.resolveAttributes(state.mAttrPadding, R.styleable.GradientDrawablePadding, 0, 0);
+            a = t.resolveAttributes(state.mAttrPadding, R.styleable.GradientDrawablePadding);
             // TODO: updateGradientDrawablePadding(a);
             a.recycle();
         }
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 639d719..7847aad 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -229,7 +229,7 @@
 
         final int[] themeAttrs = state.mThemeAttrs;
         if (themeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(themeAttrs, R.styleable.LayerDrawable, 0, 0);
+            final TypedArray a = t.resolveAttributes(themeAttrs, R.styleable.LayerDrawable);
             updateStateFromTypedArray(a);
             a.recycle();
         }
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 21992ce..3e09707 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -72,8 +72,8 @@
     private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
 
     // These are scaled to match the target density.
-    private int mBitmapWidth;
-    private int mBitmapHeight;
+    private int mBitmapWidth = -1;
+    private int mBitmapHeight = -1;
 
     NinePatchDrawable() {
         mNinePatchState = new NinePatchState();
@@ -209,7 +209,7 @@
     }
 
     private void setNinePatch(NinePatch ninePatch) {
-        if (ninePatch != mNinePatch) {
+        if (mNinePatch != ninePatch) {
             mNinePatch = ninePatch;
             if (ninePatch != null) {
                 computeBitmapSize();
@@ -339,7 +339,7 @@
     public void setTint(ColorStateList tint) {
         if (mNinePatchState.mTint != tint) {
             mNinePatchState.mTint = tint;
-            updateTintFilter();
+            computeTintFilter();
             invalidateSelf();
         }
     }
@@ -362,23 +362,20 @@
     public void setTintMode(Mode tintMode) {
         if (mNinePatchState.mTintMode != tintMode) {
             mNinePatchState.mTintMode = tintMode;
-            updateTintFilter();
+            computeTintFilter();
             invalidateSelf();
         }
     }
 
-    /**
-     * Ensures the tint filter is consistent with the current tint color and
-     * mode.
-     */
-    private void updateTintFilter() {
-        final ColorStateList tint = mNinePatchState.mTint;
-        final Mode tintMode = mNinePatchState.mTintMode;
-        if (tint != null && tintMode != null) {
-            if (mTintFilter == null) {
-                mTintFilter = new PorterDuffColorFilter(0, tintMode);
+    private void computeTintFilter() {
+        final NinePatchState state = mNinePatchState;
+        if (state.mTint != null && state.mTintMode != null) {
+            final int color = state.mTint.getColorForState(getState(), 0);
+            if (mTintFilter != null) {
+                mTintFilter.setColor(color);
+                mTintFilter.setMode(state.mTintMode);
             } else {
-                mTintFilter.setMode(tintMode);
+                mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
             }
         } else {
             mTintFilter = null;
@@ -422,139 +419,26 @@
             throws XmlPullParserException, IOException {
         super.inflate(r, parser, attrs, theme);
 
-        final TypedArray a = obtainAttributes(
-                r, theme, attrs, R.styleable.NinePatchDrawable);
-        inflateStateFromTypedArray(a);
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.NinePatchDrawable);
+        updateStateFromTypedArray(a);
         a.recycle();
     }
 
     /**
-     * Initializes the constant state from the values in the typed array.
-     */
-    private void inflateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
-        final Resources r = a.getResources();
-        final NinePatchState ninePatchState = mNinePatchState;
-
-        // Extract the theme attributes, if any.
-        final int[] themeAttrs = a.extractThemeAttrs();
-        ninePatchState.mThemeAttrs = themeAttrs;
-
-        if (themeAttrs == null || themeAttrs[R.styleable.NinePatchDrawable_dither] == 0) {
-            final boolean dither = a.getBoolean(
-                    R.styleable.NinePatchDrawable_dither, DEFAULT_DITHER);
-            ninePatchState.mDither = dither;
-        }
-
-        if (themeAttrs == null || themeAttrs[R.styleable.NinePatchDrawable_src] == 0) {
-            final int id = a.getResourceId(R.styleable.NinePatchDrawable_src, 0);
-            if (id == 0) {
-                throw new XmlPullParserException(a.getPositionDescription() +
-                        ": <nine-patch> requires a valid src attribute");
-            }
-
-            final BitmapFactory.Options options = new BitmapFactory.Options();
-            options.inDither = !ninePatchState.mDither;
-            options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi;
-
-            final Rect padding = new Rect();
-            final Rect opticalInsets = new Rect();
-            Bitmap bitmap = null;
-
-            try {
-                final TypedValue value = new TypedValue();
-                final InputStream is = r.openRawResource(id, value);
-
-                bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options);
-
-                is.close();
-            } catch (IOException e) {
-                // Ignore
-            }
-
-            if (bitmap == null) {
-                throw new XmlPullParserException(a.getPositionDescription() +
-                        ": <nine-patch> requires a valid src attribute");
-            } else if (bitmap.getNinePatchChunk() == null) {
-                throw new XmlPullParserException(a.getPositionDescription() +
-                        ": <nine-patch> requires a valid 9-patch source image");
-            }
-
-            final NinePatch ninePatch = new NinePatch(bitmap, bitmap.getNinePatchChunk());
-            ninePatchState.mNinePatch = ninePatch;
-            ninePatchState.mPadding = padding;
-            ninePatchState.mOpticalInsets = Insets.of(opticalInsets);
-        }
-
-        if (themeAttrs == null || themeAttrs[R.styleable.NinePatchDrawable_autoMirrored] == 0) {
-            final boolean autoMirrored = a.getBoolean(
-                    R.styleable.NinePatchDrawable_autoMirrored, false);
-            ninePatchState.mAutoMirrored = autoMirrored;
-        }
-
-        if (themeAttrs == null || themeAttrs[R.styleable.NinePatchDrawable_tintMode] == 0) {
-            final int tintModeValue = a.getInt(R.styleable.NinePatchDrawable_tintMode, -1);
-            ninePatchState.mTintMode = Drawable.parseTintMode(tintModeValue, Mode.SRC_IN);
-        }
-
-        if (themeAttrs == null || themeAttrs[R.styleable.NinePatchDrawable_tint] == 0) {
-            ninePatchState.mTint = a.getColorStateList(R.styleable.NinePatchDrawable_tint);
-            if (ninePatchState.mTint != null) {
-                final int color = ninePatchState.mTint.getColorForState(getState(), 0);
-                mTintFilter = new PorterDuffColorFilter(color, ninePatchState.mTintMode);
-            }
-        }
-
-        if (themeAttrs == null || themeAttrs[R.styleable.NinePatchDrawable_alpha] == 0) {
-            ninePatchState.mBaseAlpha = a.getFloat(R.styleable.NinePatchDrawable_alpha, 1.0f);
-        }
-
-        // Apply the constant state to the paint.
-        initializeWithState(ninePatchState, r);
-
-        // Push density applied by setNinePatchState into state.
-        ninePatchState.mTargetDensity = mTargetDensity;
-    }
-
-    @Override
-    public void applyTheme(Theme t) {
-        super.applyTheme(t);
-
-        final NinePatchState state = mNinePatchState;
-        if (state == null) {
-            throw new RuntimeException("Can't apply theme to <nine-patch> with no constant state");
-        }
-
-        final int[] themeAttrs = state.mThemeAttrs;
-        if (themeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(
-                    themeAttrs, R.styleable.NinePatchDrawable, 0, 0);
-            updateStateFromTypedArray(a);
-            a.recycle();
-        }
-    }
-
-    /**
      * Updates the constant state from the values in the typed array.
      */
-    private void updateStateFromTypedArray(TypedArray a) {
+    private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
         final Resources r = a.getResources();
         final NinePatchState state = mNinePatchState;
 
-        if (a.hasValue(R.styleable.NinePatchDrawable_dither)) {
-            state.mDither = a.getBoolean(R.styleable.NinePatchDrawable_dither, DEFAULT_DITHER);
-        }
+        // Extract the theme attributes, if any.
+        final int[] themeAttrs = a.extractThemeAttrs();
+        state.mThemeAttrs = themeAttrs;
 
-        if (a.hasValue(R.styleable.NinePatchDrawable_autoMirrored)) {
-            state.mAutoMirrored = a.getBoolean(R.styleable.NinePatchDrawable_autoMirrored, false);
-        }
+        state.mDither = a.getBoolean(R.styleable.NinePatchDrawable_dither, state.mDither);
 
-        if (a.hasValue(R.styleable.NinePatchDrawable_src)) {
-            final int id = a.getResourceId(R.styleable.NinePatchDrawable_src, 0);
-            if (id == 0) {
-                throw new RuntimeException(a.getPositionDescription() +
-                        ": <nine-patch> requires a valid src attribute");
-            }
-
+        final int srcResId = a.getResourceId(R.styleable.NinePatchDrawable_src, 0);
+        if (srcResId != 0) {
             final BitmapFactory.Options options = new BitmapFactory.Options();
             options.inDither = !state.mDither;
             options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi;
@@ -565,7 +449,7 @@
 
             try {
                 final TypedValue value = new TypedValue();
-                final InputStream is = r.openRawResource(id, value);
+                final InputStream is = r.openRawResource(srcResId, value);
 
                 bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options);
 
@@ -575,10 +459,10 @@
             }
 
             if (bitmap == null) {
-                throw new RuntimeException(a.getPositionDescription() +
+                throw new XmlPullParserException(a.getPositionDescription() +
                         ": <nine-patch> requires a valid src attribute");
             } else if (bitmap.getNinePatchChunk() == null) {
-                throw new RuntimeException(a.getPositionDescription() +
+                throw new XmlPullParserException(a.getPositionDescription() +
                         ": <nine-patch> requires a valid 9-patch source image");
             }
 
@@ -587,25 +471,21 @@
             state.mOpticalInsets = Insets.of(opticalInsets);
         }
 
-        if (a.hasValue(R.styleable.NinePatchDrawable_tintMode)) {
-            final int modeValue = a.getInt(R.styleable.NinePatchDrawable_tintMode, -1);
-            state.mTintMode = Drawable.parseTintMode(modeValue, Mode.SRC_IN);
+        state.mAutoMirrored = a.getBoolean(
+                R.styleable.NinePatchDrawable_autoMirrored, state.mAutoMirrored);
+        state.mBaseAlpha = a.getFloat(R.styleable.NinePatchDrawable_alpha, state.mBaseAlpha);
+
+        final int tintMode = a.getInt(R.styleable.NinePatchDrawable_tintMode, -1);
+        if (tintMode != -1) {
+            state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
         }
 
-        if (a.hasValue(R.styleable.NinePatchDrawable_tint)) {
-            final ColorStateList tint = a.getColorStateList(R.styleable.NinePatchDrawable_tint);
-            if (tint != null) {
-                state.mTint = tint;
-                final int color = tint.getColorForState(getState(), 0);
-                mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
-            }
+        final ColorStateList tint = a.getColorStateList(R.styleable.NinePatchDrawable_tint);
+        if (tint != null) {
+            state.mTint = tint;
         }
 
-        if (a.hasValue(R.styleable.NinePatchDrawable_alpha)) {
-            state.mBaseAlpha = a.getFloat(R.styleable.NinePatchDrawable_alpha, 1.0f);
-        }
-
-        // Apply the constant state to the paint.
+        // Update local properties.
         initializeWithState(state, r);
 
         // Push density applied by setNinePatchState into state.
@@ -613,6 +493,25 @@
     }
 
     @Override
+    public void applyTheme(Theme t) {
+        super.applyTheme(t);
+
+        final NinePatchState state = mNinePatchState;
+        if (state == null || state.mThemeAttrs == null) {
+            return;
+        }
+
+        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.NinePatchDrawable);
+        try {
+            updateStateFromTypedArray(a);
+        } catch (XmlPullParserException e) {
+            throw new RuntimeException(e);
+        } finally {
+            a.recycle();
+        }
+    }
+
+    @Override
     public boolean canApplyTheme() {
         return mNinePatchState != null && mNinePatchState.mThemeAttrs != null;
     }
@@ -705,17 +604,19 @@
     }
 
     final static class NinePatchState extends ConstantState {
-        NinePatch mNinePatch;
-        ColorStateList mTint;
+        // Values loaded during inflation.
+        int[] mThemeAttrs = null;
+        NinePatch mNinePatch = null;
+        ColorStateList mTint = null;
         Mode mTintMode = Mode.SRC_IN;
-        Rect mPadding;
-        Insets mOpticalInsets;
+        Rect mPadding = null;
+        Insets mOpticalInsets = Insets.NONE;
         float mBaseAlpha = 1.0f;
-        boolean mDither;
-        int[] mThemeAttrs;
-        int mChangingConfigurations;
+        boolean mDither = DEFAULT_DITHER;
         int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
-        boolean mAutoMirrored;
+        boolean mAutoMirrored = false;
+
+        int mChangingConfigurations;
 
         NinePatchState() {
             // Empty constructor.
@@ -786,6 +687,10 @@
         }
     }
 
+    /**
+     * The one constructor to rule them all. This is called by all public
+     * constructors to set the state and initialize local properties.
+     */
     private NinePatchDrawable(NinePatchState state, Resources res, Theme theme) {
         if (theme != null && state.canApplyTheme()) {
             mNinePatchState = new NinePatchState(state);
@@ -812,14 +717,12 @@
             setDither(state.mDither);
         }
 
-        if (state.mTint != null) {
-            final int color = state.mTint.getColorForState(getState(), 0);
-            mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
+        // Make a local copy of the padding.
+        if (state.mPadding != null) {
+            mPadding = new Rect(state.mPadding);
         }
 
-        final Rect statePadding = state.mPadding;
-        mPadding =  statePadding != null ? new Rect(statePadding) : null;
-
+        computeTintFilter();
         setNinePatch(state.mNinePatch);
     }
 }
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 218a057..24e8de6 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -17,227 +17,220 @@
 package android.graphics.drawable;
 
 import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
 import android.graphics.Rect;
-import android.view.animation.DecelerateInterpolator;
+import android.view.HardwareCanvas;
+import android.view.RenderNodeAnimator;
+import android.view.animation.AccelerateInterpolator;
+
+import java.util.ArrayList;
 
 /**
  * Draws a Quantum Paper ripple.
  */
 class Ripple {
-    private static final TimeInterpolator INTERPOLATOR = new DecelerateInterpolator();
+    private static final TimeInterpolator INTERPOLATOR = new AccelerateInterpolator();
 
-    /** Starting radius for a ripple. */
-    private static final int STARTING_RADIUS_DP = 16;
+    private static final float GLOBAL_SPEED = 1.0f;
+    private static final float WAVE_TOUCH_DOWN_ACCELERATION = 512.0f * GLOBAL_SPEED;
+    private static final float WAVE_TOUCH_UP_ACCELERATION = 1024.0f * GLOBAL_SPEED;
+    private static final float WAVE_OPACITY_DECAY_VELOCITY = 1.6f / GLOBAL_SPEED;
+    private static final float WAVE_OUTER_OPACITY_VELOCITY = 1.2f * GLOBAL_SPEED;
 
-    /** Radius when finger is outside view bounds. */
-    private static final int OUTSIDE_RADIUS_DP = 16;
-
-    /** Radius when finger is inside view bounds. */
-    private static final int INSIDE_RADIUS_DP = 96;
-
-    /** Margin when constraining outside touches (fraction of outer radius). */
-    private static final float OUTSIDE_MARGIN = 0.8f;
-
-    /** Resistance factor when constraining outside touches. */
-    private static final float OUTSIDE_RESISTANCE = 0.7f;
-
-    /** Minimum alpha value during a pulse animation. */
-    private static final float PULSE_MIN_ALPHA = 0.5f;
-
-    /** Duration for animating the trailing edge of the ripple. */
-    private static final int EXIT_DURATION = 600;
-
-    /** Duration for animating the leading edge of the ripple. */
-    private static final int ENTER_DURATION = 400;
-
-    /** Duration for animating the ripple alpha in and out. */
-    private static final int FADE_DURATION = 50;
-
-    /** Minimum elapsed time between start of enter and exit animations. */
-    private static final int EXIT_MIN_DELAY = 200;
-
-    /** Duration for animating between inside and outside touch. */
-    private static final int OUTSIDE_DURATION = 300;
-
-    /** Duration for animating pulses. */
-    private static final int PULSE_DURATION = 400;
-
-    /** Interval between pulses while inside and fully entered. */
-    private static final int PULSE_INTERVAL = 400;
-
-    /** Delay before pulses start. */
-    private static final int PULSE_DELAY = 500;
+    // Hardware animators.
+    private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<>();
+    private final ArrayList<RenderNodeAnimator> mPendingAnimations = new ArrayList<>();
 
     private final Drawable mOwner;
 
-    /** Bounds used for computing max radius and containment. */
+    /** Bounds used for computing max radius. */
     private final Rect mBounds;
 
-    /** Configured maximum ripple radius when the center is outside the bounds. */
-    private final int mMaxOutsideRadius;
-
-    /** Configured maximum ripple radius. */
-    private final int mMaxInsideRadius;
-
-    private ObjectAnimator mOuter;
-    private ObjectAnimator mInner;
-    private ObjectAnimator mAlpha;
+    /** Full-opacity color for drawing this ripple. */
+    private final int mColor;
 
     /** Maximum ripple radius. */
-    private int mMaxRadius;
-
     private float mOuterRadius;
-    private float mInnerRadius;
-    private float mAlphaMultiplier;
 
-    /** Center x-coordinate. */
+    // Hardware rendering properties.
+    private CanvasProperty<Paint> mPropPaint;
+    private CanvasProperty<Float> mPropRadius;
+    private CanvasProperty<Float> mPropX;
+    private CanvasProperty<Float> mPropY;
+    private CanvasProperty<Paint> mPropOuterPaint;
+    private CanvasProperty<Float> mPropOuterRadius;
+    private CanvasProperty<Float> mPropOuterX;
+    private CanvasProperty<Float> mPropOuterY;
+
+    // Software animators.
+    private ObjectAnimator mAnimRadius;
+    private ObjectAnimator mAnimOpacity;
+    private ObjectAnimator mAnimOuterOpacity;
+    private ObjectAnimator mAnimX;
+    private ObjectAnimator mAnimY;
+
+    // Software rendering properties.
+    private float mOuterOpacity = 0;
+    private float mOpacity = 1;
+    private float mRadius = 0;
+    private float mOuterX;
+    private float mOuterY;
     private float mX;
-
-    /** Center y-coordinate. */
     private float mY;
 
-    /** Whether the center is within the parent bounds. */
-    private boolean mInsideBounds;
+    private boolean mFinished;
 
-    /** Whether to pulse this ripple. */
-    private boolean mPulseEnabled;
+    /** Whether we should be drawing hardware animations. */
+    private boolean mHardwareAnimating;
 
-    /** Temporary hack since we can't check finished state of animator. */
-    private boolean mExitFinished;
-
-    /** Whether this ripple has ever moved. */
-    private boolean mHasMoved;
+    /** Whether we can use hardware acceleration for the exit animation. */
+    private boolean mCanUseHardware;
 
     /**
      * Creates a new ripple.
      */
-    public Ripple(Drawable owner, Rect bounds, float density, boolean pulseEnabled) {
+    public Ripple(Drawable owner, Rect bounds, int color) {
         mOwner = owner;
         mBounds = bounds;
-        mPulseEnabled = pulseEnabled;
+        mColor = color | 0xFF000000;
 
-        mOuterRadius = (int) (density * STARTING_RADIUS_DP + 0.5f);
-        mMaxOutsideRadius = (int) (density * OUTSIDE_RADIUS_DP + 0.5f);
-        mMaxInsideRadius = (int) (density * INSIDE_RADIUS_DP + 0.5f);
-        mMaxRadius = Math.min(mMaxInsideRadius, Math.max(bounds.width(), bounds.height()));
+        final float halfWidth = bounds.width() / 2.0f;
+        final float halfHeight = bounds.height() / 2.0f;
+        mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight);
+        mOuterX = 0;
+        mOuterY = 0;
     }
 
-    public void setOuterRadius(float r) {
-        mOuterRadius = r;
+    public void setRadius(float r) {
+        mRadius = r;
         invalidateSelf();
     }
 
-    public float getOuterRadius() {
-        return mOuterRadius;
+    public float getRadius() {
+        return mRadius;
     }
 
-    public void setInnerRadius(float r) {
-        mInnerRadius = r;
+    public void setOpacity(float a) {
+        mOpacity = a;
         invalidateSelf();
     }
 
-    public float getInnerRadius() {
-        return mInnerRadius;
+    public float getOpacity() {
+        return mOpacity;
     }
 
-    public void setAlphaMultiplier(float a) {
-        mAlphaMultiplier = a;
+    public void setOuterOpacity(float a) {
+        mOuterOpacity = a;
         invalidateSelf();
     }
 
-    public float getAlphaMultiplier() {
-        return mAlphaMultiplier;
+    public float getOuterOpacity() {
+        return mOuterOpacity;
+    }
+
+    public void setX(float x) {
+        mX = x;
+        invalidateSelf();
+    }
+
+    public float getX() {
+        return mX;
+    }
+
+    public void setY(float y) {
+        mY = y;
+        invalidateSelf();
+    }
+
+    public float getY() {
+        return mY;
     }
 
     /**
      * Returns whether this ripple has finished exiting.
      */
     public boolean isFinished() {
-        return mExitFinished;
+        return mFinished;
     }
 
     /**
-     * Called when the bounds change.
-     */
-    public void onBoundsChanged() {
-        mMaxRadius = Math.min(mMaxInsideRadius, Math.max(mBounds.width(), mBounds.height()));
-
-        updateInsideBounds();
-    }
-
-    private void updateInsideBounds() {
-        final boolean insideBounds = mBounds.contains((int) (mX + 0.5f), (int) (mY + 0.5f));
-        if (mInsideBounds != insideBounds || !mHasMoved) {
-            mInsideBounds = insideBounds;
-            mHasMoved = true;
-
-            if (insideBounds) {
-                enter();
-            } else {
-                outside();
-            }
-        }
-    }
-
-    /**
-     * Draws the ripple using the specified paint.
+     * Draws the ripple centered at (0,0) using the specified paint.
      */
     public boolean draw(Canvas c, Paint p) {
-        final Rect bounds = mBounds;
-        final float outerRadius = mOuterRadius;
-        final float innerRadius = mInnerRadius;
-        final float alphaMultiplier = mAlphaMultiplier;
+        final boolean canUseHardware = c.isHardwareAccelerated();
+        if (mCanUseHardware != canUseHardware && mCanUseHardware) {
+            // We've switched from hardware to non-hardware mode. Panic.
+            cancelHardwareAnimations();
+        }
+        mCanUseHardware = canUseHardware;
+
+        final boolean hasContent;
+        if (canUseHardware && mHardwareAnimating) {
+            hasContent = drawHardware((HardwareCanvas) c);
+        } else {
+            hasContent = drawSoftware(c, p);
+        }
+
+        return hasContent;
+    }
+
+    private boolean drawHardware(HardwareCanvas c) {
+        // If we have any pending hardware animations, cancel any running
+        // animations and start those now.
+        final ArrayList<RenderNodeAnimator> pendingAnimations = mPendingAnimations;
+        final int N = pendingAnimations == null ? 0 : pendingAnimations.size();
+        if (N > 0) {
+            cancelHardwareAnimations();
+
+            for (int i = 0; i < N; i++) {
+                pendingAnimations.get(i).setTarget(c);
+                pendingAnimations.get(i).start();
+            }
+
+            mRunningAnimations.addAll(pendingAnimations);
+            pendingAnimations.clear();
+        }
+
+        c.drawCircle(mPropOuterX, mPropOuterY, mPropOuterRadius, mPropOuterPaint);
+        c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint);
+
+        return true;
+    }
+
+    private boolean drawSoftware(Canvas c, Paint p) {
+        final float radius = mRadius;
+        final float opacity = mOpacity;
+        final float outerOpacity = mOuterOpacity;
 
         // Cache the paint alpha so we can restore it later.
         final int paintAlpha = p.getAlpha();
-        final int alpha = (int) (paintAlpha * alphaMultiplier + 0.5f);
+        final int alpha = (int) (255 * opacity + 0.5f);
+        final int outerAlpha = (int) (255 * outerOpacity + 0.5f);
 
-        // Apply resistance effect when outside bounds.
-        final float x;
-        final float y;
-        if (mInsideBounds) {
-            x = mX;
-            y = mY;
-        } else {
-            // TODO: We need to do this outside of draw() so that our dirty
-            // bounds accurately reflect resistance.
-            x = looseConstrain(mX, bounds.left, bounds.right,
-                    mOuterRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
-            y = looseConstrain(mY, bounds.top, bounds.bottom,
-                    mOuterRadius * OUTSIDE_MARGIN, OUTSIDE_RESISTANCE);
+        boolean hasContent = false;
+
+        if (outerAlpha > 0 && alpha > 0) {
+            p.setAlpha(Math.min(alpha, outerAlpha));
+            p.setStyle(Style.FILL);
+            c.drawCircle(mOuterX, mOuterY, mOuterRadius, p);
+            hasContent = true;
         }
 
-        final boolean hasContent;
-        if (alphaMultiplier <= 0 || innerRadius >= outerRadius) {
-            // Nothing to draw.
-            hasContent = false;
-        } else if (innerRadius > 0) {
-            // Draw a ring.
-            final float strokeWidth = outerRadius - innerRadius;
-            final float strokeRadius = innerRadius + strokeWidth / 2.0f;
-            p.setAlpha(alpha);
-            p.setStyle(Style.STROKE);
-            p.setStrokeWidth(strokeWidth);
-            c.drawCircle(x, y, strokeRadius, p);
-            hasContent = true;
-        } else if (outerRadius > 0) {
-            // Draw a circle.
+        if (opacity > 0 && radius > 0) {
             p.setAlpha(alpha);
             p.setStyle(Style.FILL);
-            c.drawCircle(x, y, outerRadius, p);
+            c.drawCircle(mX, mY, radius, p);
             hasContent = true;
-        } else {
-            hasContent = false;
         }
 
         p.setAlpha(paintAlpha);
+
         return hasContent;
     }
 
@@ -245,156 +238,279 @@
      * Returns the maximum bounds for this ripple.
      */
     public void getBounds(Rect bounds) {
+        final int outerX = (int) mOuterX;
+        final int outerY = (int) mOuterY;
+        final int r = (int) mOuterRadius;
+        bounds.set(outerX - r, outerY - r, outerX + r, outerY + r);
+
         final int x = (int) mX;
         final int y = (int) mY;
-        final int maxRadius = mMaxRadius;
-        bounds.set(x - maxRadius, y - maxRadius, x + maxRadius, y + maxRadius);
+        bounds.union(x - r, y - r, x + r, y + r);
     }
 
     /**
-     * Updates the center coordinates.
+     * Starts the enter animation at the specified absolute coordinates.
      */
-    public void move(float x, float y) {
-        mX = x;
-        mY = y;
+    public void enter(float x, float y) {
+        mX = x - mBounds.exactCenterX();
+        mY = y - mBounds.exactCenterY();
 
-        updateInsideBounds();
+        final int radiusDuration = (int)
+                (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION) + 0.5);
+        final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_VELOCITY);
+
+        final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radius", 0, mOuterRadius);
+        radius.setAutoCancel(true);
+        radius.setDuration(radiusDuration);
+
+        final ObjectAnimator cX = ObjectAnimator.ofFloat(this, "x", mOuterX);
+        cX.setAutoCancel(true);
+        cX.setDuration(radiusDuration);
+
+        final ObjectAnimator cY = ObjectAnimator.ofFloat(this, "y", mOuterY);
+        cY.setAutoCancel(true);
+        cY.setDuration(radiusDuration);
+
+        final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1);
+        outer.setAutoCancel(true);
+        outer.setDuration(outerDuration);
+
+        mAnimRadius = radius;
+        mAnimOuterOpacity = outer;
+        mAnimX = cX;
+        mAnimY = cY;
+
+        // Enter animations always run on the UI thread, since it's unlikely
+        // that anything interesting is happening until the user lifts their
+        // finger.
+        radius.start();
+        outer.start();
+        cX.start();
+        cY.start();
+    }
+
+    /**
+     * Starts the exit animation.
+     */
+    public void exit() {
+        cancelSoftwareAnimations();
+
+        final float remaining;
+        if (mAnimRadius != null && mAnimRadius.isRunning()) {
+            remaining = mOuterRadius - mRadius;
+        } else {
+            remaining = mOuterRadius;
+        }
+
+        final int radiusDuration = (int) (1000 * Math.sqrt(remaining / (WAVE_TOUCH_UP_ACCELERATION
+                + WAVE_TOUCH_DOWN_ACCELERATION)) + 0.5);
+        final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f);
+
+        // Determine at what time the inner and outer opacity intersect.
+        // inner(t) = mOpacity - t * WAVE_OPACITY_DECAY_VELOCITY / 1000
+        // outer(t) = mOuterOpacity + t * WAVE_OUTER_OPACITY_VELOCITY / 1000
+        final int outerInflection = Math.max(0, (int) (1000 * (mOpacity - mOuterOpacity)
+                / (WAVE_OPACITY_DECAY_VELOCITY + WAVE_OUTER_OPACITY_VELOCITY) + 0.5f));
+        final int inflectionOpacity = (int) (255 * (mOuterOpacity + outerInflection
+                * WAVE_OUTER_OPACITY_VELOCITY / 1000) + 0.5f);
+
+        if (mCanUseHardware) {
+            exitHardware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity);
+        } else {
+            exitSoftware(radiusDuration, opacityDuration, outerInflection, inflectionOpacity);
+        }
+    }
+
+    private void exitHardware(int radiusDuration, int opacityDuration, int outerInflection,
+            int inflectionOpacity) {
+        mPendingAnimations.clear();
+
+        final Paint outerPaint = new Paint();
+        outerPaint.setAntiAlias(true);
+        outerPaint.setColor(mColor);
+        outerPaint.setAlpha((int) (255 * mOuterOpacity + 0.5f));
+        outerPaint.setStyle(Style.FILL);
+        mPropOuterPaint = CanvasProperty.createPaint(outerPaint);
+        mPropOuterRadius = CanvasProperty.createFloat(mOuterRadius);
+        mPropOuterX = CanvasProperty.createFloat(mOuterX);
+        mPropOuterY = CanvasProperty.createFloat(mOuterY);
+
+        final Paint paint = new Paint();
+        paint.setAntiAlias(true);
+        paint.setColor(mColor);
+        paint.setAlpha((int) (255 * mOpacity + 0.5f));
+        paint.setStyle(Style.FILL);
+        mPropPaint = CanvasProperty.createPaint(paint);
+        mPropRadius = CanvasProperty.createFloat(mRadius);
+        mPropX = CanvasProperty.createFloat(mX);
+        mPropY = CanvasProperty.createFloat(mY);
+
+        final RenderNodeAnimator radius = new RenderNodeAnimator(mPropRadius, mOuterRadius);
+        radius.setDuration(radiusDuration);
+
+        final RenderNodeAnimator x = new RenderNodeAnimator(mPropX, mOuterX);
+        x.setDuration(radiusDuration);
+
+        final RenderNodeAnimator y = new RenderNodeAnimator(mPropY, mOuterY);
+        y.setDuration(radiusDuration);
+
+        final RenderNodeAnimator opacity = new RenderNodeAnimator(mPropPaint,
+                RenderNodeAnimator.PAINT_ALPHA, 0);
+        opacity.setDuration(opacityDuration);
+        opacity.addListener(mAnimationListener);
+
+        final RenderNodeAnimator outerOpacity;
+        if (outerInflection > 0) {
+            // Outer opacity continues to increase for a bit.
+            outerOpacity = new RenderNodeAnimator(
+                    mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, inflectionOpacity);
+            outerOpacity.setDuration(outerInflection);
+
+            // Chain the outer opacity exit animation.
+            final int outerDuration = opacityDuration - outerInflection;
+            if (outerDuration > 0) {
+                final RenderNodeAnimator outerFadeOut = new RenderNodeAnimator(
+                        mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
+                outerFadeOut.setDuration(outerDuration);
+                outerFadeOut.setStartDelay(outerInflection);
+
+                mPendingAnimations.add(outerFadeOut);
+            }
+        } else {
+            outerOpacity = new RenderNodeAnimator(
+                    mPropOuterPaint, RenderNodeAnimator.PAINT_ALPHA, 0);
+            outerOpacity.setDuration(opacityDuration);
+        }
+
+        mPendingAnimations.add(radius);
+        mPendingAnimations.add(opacity);
+        mPendingAnimations.add(outerOpacity);
+        mPendingAnimations.add(x);
+        mPendingAnimations.add(y);
+
+        mHardwareAnimating = true;
+
         invalidateSelf();
     }
 
-    /**
-     * Starts the exit animation. If {@link #enter()} was called recently, the
-     * animation may be postponed.
-     */
-    public void exit() {
-        mExitFinished = false;
+    private void exitSoftware(int radiusDuration, int opacityDuration, int outerInflection,
+            float inflectionOpacity) {
+        final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radius", mOuterRadius);
+        radius.setAutoCancel(true);
+        radius.setDuration(radiusDuration);
 
-        final ObjectAnimator inner = ObjectAnimator.ofFloat(this, "innerRadius", 0, mMaxRadius);
-        inner.setAutoCancel(true);
-        inner.setDuration(EXIT_DURATION);
-        inner.setInterpolator(INTERPOLATOR);
-        inner.addListener(mAnimationListener);
+        final ObjectAnimator x = ObjectAnimator.ofFloat(this, "x", mOuterX);
+        x.setAutoCancel(true);
+        x.setDuration(radiusDuration);
 
-        if (mOuter != null && mOuter.isStarted()) {
-            // If we haven't been running the enter animation for long enough,
-            // delay the exit animator.
-            final int elapsed = (int) (mOuter.getAnimatedFraction() * mOuter.getDuration());
-            final int delay = Math.max(0, EXIT_MIN_DELAY - elapsed);
-            inner.setStartDelay(delay);
+        final ObjectAnimator y = ObjectAnimator.ofFloat(this, "y", mOuterY);
+        y.setAutoCancel(true);
+        y.setDuration(radiusDuration);
+
+        final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, "opacity", 0);
+        opacity.setAutoCancel(true);
+        opacity.setDuration(opacityDuration);
+        opacity.addListener(mAnimationListener);
+
+        final ObjectAnimator outerOpacity;
+        if (outerInflection > 0) {
+            // Outer opacity continues to increase for a bit.
+            outerOpacity = ObjectAnimator.ofFloat(this, "outerOpacity", inflectionOpacity);
+            outerOpacity.setDuration(outerInflection);
+
+            // Chain the outer opacity exit animation.
+            final int outerDuration = opacityDuration - outerInflection;
+            outerOpacity.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    final ObjectAnimator outerFadeOut = ObjectAnimator.ofFloat(Ripple.this,
+                            "outerOpacity", 0);
+                    outerFadeOut.setDuration(outerDuration);
+
+                    mAnimOuterOpacity = outerFadeOut;
+
+                    outerFadeOut.start();
+                }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    animation.removeListener(this);
+                }
+            });
+        } else {
+            outerOpacity = ObjectAnimator.ofFloat(this, "outerOpacity", 0);
+            outerOpacity.setDuration(opacityDuration);
         }
 
-        inner.start();
+        mAnimRadius = radius;
+        mAnimOpacity = opacity;
+        mAnimOuterOpacity = outerOpacity;
+        mAnimX = opacity;
+        mAnimY = opacity;
 
-        final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 0);
-        alpha.setAutoCancel(true);
-        alpha.setDuration(EXIT_DURATION);
-        alpha.start();
-
-        mInner = inner;
-        mAlpha = alpha;
+        radius.start();
+        opacity.start();
+        outerOpacity.start();
+        x.start();
+        y.start();
     }
 
     /**
      * Cancel all animations.
      */
     public void cancel() {
-        if (mInner != null) {
-            mInner.cancel();
+        cancelSoftwareAnimations();
+        cancelHardwareAnimations();
+    }
+
+    private void cancelSoftwareAnimations() {
+        if (mAnimRadius != null) {
+            mAnimRadius.cancel();
         }
 
-        if (mOuter != null) {
-            mOuter.cancel();
+        if (mAnimOpacity != null) {
+            mAnimOpacity.cancel();
         }
 
-        if (mAlpha != null) {
-            mAlpha.cancel();
+        if (mAnimOuterOpacity != null) {
+            mAnimOuterOpacity.cancel();
         }
+
+        if (mAnimX != null) {
+            mAnimX.cancel();
+        }
+
+        if (mAnimY != null) {
+            mAnimY.cancel();
+        }
+    }
+
+    /**
+     * Cancels any running hardware animations.
+     */
+    private void cancelHardwareAnimations() {
+        final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations;
+        final int N = runningAnimations == null ? 0 : runningAnimations.size();
+        for (int i = 0; i < N; i++) {
+            runningAnimations.get(i).cancel();
+        }
+
+        runningAnimations.clear();
     }
 
     private void invalidateSelf() {
         mOwner.invalidateSelf();
     }
 
-    /**
-     * Starts the enter animation.
-     */
-    private void enter() {
-        final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerRadius", mMaxRadius);
-        outer.setAutoCancel(true);
-        outer.setDuration(ENTER_DURATION);
-        outer.setInterpolator(INTERPOLATOR);
-        outer.start();
-
-        final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1);
-        if (mPulseEnabled) {
-            alpha.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    final ObjectAnimator pulse = ObjectAnimator.ofFloat(
-                            this, "alphaMultiplier", 1, PULSE_MIN_ALPHA);
-                    pulse.setAutoCancel(true);
-                    pulse.setDuration(PULSE_DURATION + PULSE_INTERVAL);
-                    pulse.setRepeatCount(ObjectAnimator.INFINITE);
-                    pulse.setRepeatMode(ObjectAnimator.REVERSE);
-                    pulse.setStartDelay(PULSE_DELAY);
-                    pulse.start();
-
-                    mAlpha = pulse;
-                }
-            });
-        }
-        alpha.setAutoCancel(true);
-        alpha.setDuration(FADE_DURATION);
-        alpha.start();
-
-        mOuter = outer;
-        mAlpha = alpha;
-    }
-
-    /**
-     * Starts the outside transition animation.
-     */
-    private void outside() {
-        final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerRadius", mMaxOutsideRadius);
-        outer.setAutoCancel(true);
-        outer.setDuration(OUTSIDE_DURATION);
-        outer.setInterpolator(INTERPOLATOR);
-        outer.start();
-
-        final ObjectAnimator alpha = ObjectAnimator.ofFloat(this, "alphaMultiplier", 1);
-        alpha.setAutoCancel(true);
-        alpha.setDuration(FADE_DURATION);
-        alpha.start();
-
-        mOuter = outer;
-        mAlpha = alpha;
-    }
-
-    /**
-     * Constrains a value within a specified asymptotic margin outside a minimum
-     * and maximum.
-     */
-    private static float looseConstrain(float value, float min, float max, float margin,
-            float factor) {
-        // TODO: Can we use actual spring physics here?
-        if (value < min) {
-            return min - Math.min(margin, (float) Math.pow(min - value, factor));
-        } else if (value > max) {
-            return max + Math.min(margin, (float) Math.pow(value - max, factor));
-        } else {
-            return value;
-        }
-    }
-
-    private final AnimatorListener mAnimationListener = new AnimatorListenerAdapter() {
+    private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
-            if (animation == mInner) {
-                mExitFinished = true;
-                mOuterRadius = 0;
-                mInnerRadius = 0;
-                mAlphaMultiplier = 1;
-            }
+            mFinished = true;
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mFinished = true;
         }
     };
 }
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 0097183..a55a4b2 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -24,6 +24,7 @@
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.PointF;
 import android.graphics.PorterDuff.Mode;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
@@ -33,6 +34,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.R;
+import com.android.org.bouncycastle.util.Arrays;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -40,11 +42,36 @@
 import java.io.IOException;
 
 /**
- * Documentation pending.
+ * Drawable that shows a ripple effect in response to state changes. The
+ * anchoring position of the ripple for a given state may be specified by
+ * calling {@link #setHotspot(int, float, float)} with the corresponding state
+ * attribute identifier.
+ * <p>
+ * A touch feedback drawable may contain multiple child layers, including a
+ * special mask layer that is not drawn to the screen. A single layer may be set
+ * as the mask by specifying its android:id value as {@link android.R.id#mask}.
+ * <p>
+ * If a mask layer is set, the ripple effect will be masked against that layer
+ * before it is blended onto the composite of the remaining child layers.
+ * <p>
+ * If no mask layer is set, the ripple effect is simply blended onto the
+ * composite of the child layers using the specified
+ * {@link android.R.styleable#TouchFeedbackDrawable_tintMode}.
+ * <p>
+ * If no child layers or mask is specified and the ripple is set as a View
+ * background, the ripple will be blended onto the first available parent
+ * background within the View's hierarchy using the specified
+ * {@link android.R.styleable#TouchFeedbackDrawable_tintMode}. In this case, the
+ * drawing region may extend outside of the Drawable bounds.
+ *
+ * @attr ref android.R.styleable#DrawableStates_state_focused
+ * @attr ref android.R.styleable#DrawableStates_state_pressed
  */
 public class TouchFeedbackDrawable extends LayerDrawable {
     private static final String LOG_TAG = TouchFeedbackDrawable.class.getSimpleName();
     private static final PorterDuffXfermode DST_IN = new PorterDuffXfermode(Mode.DST_IN);
+    private static final PorterDuffXfermode DST_ATOP = new PorterDuffXfermode(Mode.DST_ATOP);
+    private static final PorterDuffXfermode SRC_ATOP = new PorterDuffXfermode(Mode.SRC_ATOP);
     private static final PorterDuffXfermode SRC_OVER = new PorterDuffXfermode(Mode.SRC_OVER);
 
     /** The maximum number of ripples supported. */
@@ -63,10 +90,22 @@
 
     private final TouchFeedbackState mState;
 
-    /** Lazily-created map of touch hotspot IDs to ripples. */
-    private SparseArray<Ripple> mRipples;
+    /**
+     * Lazily-created map of pending hotspot locations. These may be modified by
+     * calls to {@link #setHotspot(int, float, float)}.
+     */
+    private SparseArray<PointF> mPendingHotspots;
 
-    /** Lazily-created array of actively animating ripples. */
+    /**
+     * Lazily-created map of active hotspot locations. These may be modified by
+     * calls to {@link #setHotspot(int, float, float)}.
+     */
+    private SparseArray<Ripple> mActiveHotspots;
+
+    /**
+     * Lazily-created array of actively animating ripples. Inactive ripples are
+     * pruned during draw(). The locations of these will not change.
+     */
     private Ripple[] mAnimatingRipples;
     private int mAnimatingRipplesCount = 0;
 
@@ -96,24 +135,18 @@
     protected boolean onStateChange(int[] stateSet) {
         super.onStateChange(stateSet);
 
-        // TODO: Implicitly tie states to ripple IDs. For now, just clear
-        // focused and pressed if they aren't in the state set.
-        boolean hasFocused = false;
-        boolean hasPressed = false;
-        for (int i = 0; i < stateSet.length; i++) {
-            if (stateSet[i] == R.attr.state_pressed) {
-                hasPressed = true;
-            } else if (stateSet[i] == R.attr.state_focused) {
-                hasFocused = true;
-            }
-        }
-
-        if (!hasPressed) {
+        final boolean pressed = Arrays.contains(stateSet, R.attr.state_pressed);
+        if (!pressed) {
             removeHotspot(R.attr.state_pressed);
+        } else {
+            activateHotspot(R.attr.state_pressed);
         }
 
-        if (!hasFocused) {
+        final boolean focused = Arrays.contains(stateSet, R.attr.state_focused);
+        if (!focused) {
             removeHotspot(R.attr.state_focused);
+        } else {
+            activateHotspot(R.attr.state_focused);
         }
 
         if (mRipplePaint != null && mState.mTint != null) {
@@ -138,19 +171,7 @@
             mHotspotBounds.set(bounds);
         }
 
-        onHotspotBoundsChange();
-    }
-
-    private void onHotspotBoundsChange() {
-        final int x = mHotspotBounds.centerX();
-        final int y = mHotspotBounds.centerY();
-        final int N = mAnimatingRipplesCount;
-        for (int i = 0; i < N; i++) {
-            if (mState.mPinned) {
-                mAnimatingRipples[i].move(x, y);
-            }
-            mAnimatingRipples[i].onBoundsChanged();
-        }
+        invalidateSelf();
     }
 
     @Override
@@ -172,7 +193,7 @@
 
     @Override
     public boolean isStateful() {
-        return super.isStateful() || mState.mTint != null && mState.mTint.isStateful();
+        return true;
     }
 
     /**
@@ -213,7 +234,7 @@
             throws XmlPullParserException, IOException {
         final TypedArray a = obtainAttributes(
                 r, theme, attrs, R.styleable.TouchFeedbackDrawable);
-        inflateStateFromTypedArray(a);
+        updateStateFromTypedArray(a);
         a.recycle();
 
         super.inflate(r, parser, attrs, theme);
@@ -245,25 +266,23 @@
     /**
      * Initializes the constant state from the values in the typed array.
      */
-    private void inflateStateFromTypedArray(TypedArray a) {
+    private void updateStateFromTypedArray(TypedArray a) {
         final TouchFeedbackState state = mState;
 
         // Extract the theme attributes, if any.
-        final int[] themeAttrs = a.extractThemeAttrs();
-        state.mTouchThemeAttrs = themeAttrs;
+        state.mTouchThemeAttrs = a.extractThemeAttrs();
 
-        if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_tint] == 0) {
-            mState.mTint = a.getColorStateList(R.styleable.TouchFeedbackDrawable_tint);
+        final ColorStateList tint = a.getColorStateList(R.styleable.TouchFeedbackDrawable_tint);
+        if (tint != null) {
+            mState.mTint = tint;
         }
 
-        if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_tintMode] == 0) {
-            mState.setTintMode(Drawable.parseTintMode(
-                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
+        final int tintMode = a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1);
+        if (tintMode != -1) {
+            mState.setTintMode(Drawable.parseTintMode(tintMode, Mode.SRC_ATOP));
         }
 
-        if (themeAttrs == null || themeAttrs[R.styleable.TouchFeedbackDrawable_pinned] == 0) {
-            mState.mPinned = a.getBoolean(R.styleable.TouchFeedbackDrawable_pinned, false);
-        }
+        mState.mPinned = a.getBoolean(R.styleable.TouchFeedbackDrawable_pinned, mState.mPinned);
     }
 
     /**
@@ -283,38 +302,14 @@
         super.applyTheme(t);
 
         final TouchFeedbackState state = mState;
-        if (state == null) {
-            throw new RuntimeException(
-                    "Can't apply theme to <touch-feedback> with no constant state");
+        if (state == null || state.mTouchThemeAttrs == null) {
+            return;
         }
 
-        final int[] themeAttrs = state.mTouchThemeAttrs;
-        if (themeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(
-                    themeAttrs, R.styleable.TouchFeedbackDrawable, 0, 0);
-            updateStateFromTypedArray(a);
-            a.recycle();
-        }
-    }
-
-    /**
-     * Updates the constant state from the values in the typed array.
-     */
-    private void updateStateFromTypedArray(TypedArray a) {
-        final TouchFeedbackState state = mState;
-
-        if (a.hasValue(R.styleable.TouchFeedbackDrawable_tint)) {
-            state.mTint = a.getColorStateList(R.styleable.TouchFeedbackDrawable_tint);
-        }
-
-        if (a.hasValue(R.styleable.TouchFeedbackDrawable_tintMode)) {
-            mState.setTintMode(Drawable.parseTintMode(
-                    a.getInt(R.styleable.TouchFeedbackDrawable_tintMode, -1), Mode.SRC_ATOP));
-        }
-
-        if (a.hasValue(R.styleable.TouchFeedbackDrawable_pinned)) {
-            mState.mPinned = a.getBoolean(R.styleable.TouchFeedbackDrawable_pinned, false);
-        }
+        final TypedArray a = t.resolveAttributes(state.mTouchThemeAttrs,
+                R.styleable.TouchFeedbackDrawable);
+        updateStateFromTypedArray(a);
+        a.recycle();
     }
 
     @Override
@@ -329,59 +324,123 @@
 
     @Override
     public void setHotspot(int id, float x, float y) {
-        if (mRipples == null) {
-            mRipples = new SparseArray<Ripple>();
-            mAnimatingRipples = new Ripple[MAX_RIPPLES];
+        if (mState.mPinned && !circleContains(mHotspotBounds, x, y)) {
+            x = mHotspotBounds.exactCenterX();
+            y = mHotspotBounds.exactCenterY();
         }
 
-        if (mAnimatingRipplesCount >= MAX_RIPPLES) {
-            Log.e(LOG_TAG, "Max ripple count exceeded", new RuntimeException());
+        final int[] stateSet = getState();
+        if (!Arrays.contains(stateSet, id)) {
+            // The hotspot is not active, so just modify the pending location.
+            getOrCreatePendingHotspot(id).set(x, y);
             return;
         }
 
-        final Ripple ripple = mRipples.get(id);
-        if (ripple == null) {
-            final Rect bounds = mHotspotBounds;
-            if (mState.mPinned) {
-                x = bounds.exactCenterX();
-                y = bounds.exactCenterY();
-            }
-
-            // TODO: Clean this up in the API.
-            final boolean pulse = (id != R.attr.state_focused);
-            final Ripple newRipple = new Ripple(this, bounds, mDensity, pulse);
-            newRipple.move(x, y);
-
-            mAnimatingRipples[mAnimatingRipplesCount++] = newRipple;
-            mRipples.put(id, newRipple);
-        } else if (mState.mPinned) {
-            final Rect bounds = mHotspotBounds;
-            x = bounds.exactCenterX();
-            y = bounds.exactCenterY();
-            ripple.move(x, y);
-        } else {
-            ripple.move(x, y);
+        if (mAnimatingRipplesCount >= MAX_RIPPLES) {
+            // This should never happen unless the user is tapping like a maniac
+            // or there is a bug that's preventing ripples from being removed.
+            Log.d(LOG_TAG, "Max ripple count exceeded", new RuntimeException());
+            return;
         }
+
+        if (mActiveHotspots == null) {
+            mActiveHotspots = new SparseArray<Ripple>();
+            mAnimatingRipples = new Ripple[MAX_RIPPLES];
+        }
+
+        final Ripple ripple = mActiveHotspots.get(id);
+        if (ripple != null) {
+            // The hotspot is active, but we can't move it because it's probably
+            // busy animating the center position.
+            return;
+        }
+
+        // The hotspot needs to be made active.
+        createActiveHotspot(id, x, y);
+    }
+
+    private boolean circleContains(Rect bounds, float x, float y) {
+        final float pX = bounds.exactCenterX() - x;
+        final float pY = bounds.exactCenterY() - y;
+        final double pointRadius = Math.sqrt(pX * pX + pY * pY);
+
+        final float bX = bounds.width() / 2.0f;
+        final float bY = bounds.height() / 2.0f;
+        final double boundsRadius = Math.sqrt(bX * bX + bY * bY);
+
+        return pointRadius < boundsRadius;
+    }
+
+    private PointF getOrCreatePendingHotspot(int id) {
+        final PointF p;
+        if (mPendingHotspots == null) {
+            mPendingHotspots = new SparseArray<>(2);
+            p = null;
+        } else {
+            p = mPendingHotspots.get(id);
+        }
+
+        if (p == null) {
+            final PointF newPoint = new PointF();
+            mPendingHotspots.put(id, newPoint);
+            return newPoint;
+        } else {
+            return p;
+        }
+    }
+
+    /**
+     * Moves a hotspot from pending to active.
+     */
+    private void activateHotspot(int id) {
+        final SparseArray<PointF> pendingHotspots = mPendingHotspots;
+        if (pendingHotspots != null) {
+            final int index = pendingHotspots.indexOfKey(id);
+            if (index >= 0) {
+                final PointF hotspot = pendingHotspots.valueAt(index);
+                pendingHotspots.removeAt(index);
+                createActiveHotspot(id, hotspot.x, hotspot.y);
+            }
+        }
+    }
+
+    /**
+     * Creates an active hotspot at the specified location.
+     */
+    private void createActiveHotspot(int id, float x, float y) {
+        final int color = mState.mTint.getColorForState(getState(), Color.TRANSPARENT);
+        final Ripple newRipple = new Ripple(this, mHotspotBounds, color);
+        newRipple.enter(x, y);
+
+        if (mAnimatingRipples == null) {
+            mAnimatingRipples = new Ripple[MAX_RIPPLES];
+        }
+        mAnimatingRipples[mAnimatingRipplesCount++] = newRipple;
+
+        if (mActiveHotspots == null) {
+            mActiveHotspots = new SparseArray<Ripple>();
+        }
+        mActiveHotspots.put(id, newRipple);
     }
 
     @Override
     public void removeHotspot(int id) {
-        if (mRipples == null) {
+        if (mActiveHotspots == null) {
             return;
         }
 
-        final Ripple ripple = mRipples.get(id);
+        final Ripple ripple = mActiveHotspots.get(id);
         if (ripple != null) {
             ripple.exit();
 
-            mRipples.remove(id);
+            mActiveHotspots.remove(id);
         }
     }
 
     @Override
     public void clearHotspots() {
-        if (mRipples != null) {
-            mRipples.clear();
+        if (mActiveHotspots != null) {
+            mActiveHotspots.clear();
         }
 
         final int count = mAnimatingRipplesCount;
@@ -402,7 +461,6 @@
     public void setHotspotBounds(int left, int top, int right, int bottom) {
         mOverrideBounds = true;
         mHotspotBounds.set(left, top, right, bottom);
-        onHotspotBoundsChange();
     }
 
     @Override
@@ -412,9 +470,9 @@
         final ChildDrawable[] array = mLayerState.mChildren;
         final boolean maskOnly = mState.mMask != null && N == 1;
 
-        int restoreToCount = drawRippleLayer(canvas, bounds, maskOnly);
+        int restoreToCount = drawRippleLayer(canvas, maskOnly);
 
-        if (restoreToCount >= 0) { 
+        if (restoreToCount >= 0) {
             // We have a ripple layer that contains ripples. If we also have an
             // explicit mask drawable, apply it now using DST_IN blending.
             if (mState.mMask != null) {
@@ -450,7 +508,7 @@
         }
     }
 
-    private int drawRippleLayer(Canvas canvas, Rect bounds, boolean maskOnly) {
+    private int drawRippleLayer(Canvas canvas, boolean maskOnly) {
         final int count = mAnimatingRipplesCount;
         if (count == 0) {
             return -1;
@@ -458,7 +516,7 @@
 
         final Ripple[] ripples = mAnimatingRipples;
         final boolean projected = isProjected();
-        final Rect layerBounds = projected ? getDirtyBounds() : bounds;
+        final Rect layerBounds = projected ? getDirtyBounds() : getBounds();
 
         // Separate the ripple color and alpha channel. The alpha will be
         // applied when we merge the ripples down to the canvas.
@@ -479,6 +537,7 @@
 
         boolean drewRipples = false;
         int restoreToCount = -1;
+        int restoreTranslate = -1;
         int animatingCount = 0;
 
         // Draw ripples and update the animating ripples array.
@@ -509,6 +568,10 @@
                 restoreToCount = canvas.saveLayer(layerBounds.left, layerBounds.top,
                         layerBounds.right, layerBounds.bottom, layerPaint);
                 layerPaint.setAlpha(255);
+
+                restoreTranslate = canvas.save();
+                // Translate the canvas to the current hotspot bounds.
+                canvas.translate(mHotspotBounds.exactCenterX(), mHotspotBounds.exactCenterY());
             }
 
             drewRipples |= ripple.draw(canvas, ripplePaint);
@@ -519,6 +582,11 @@
 
         mAnimatingRipplesCount = animatingCount;
 
+        // Always restore the translation.
+        if (restoreTranslate >= 0) {
+            canvas.restoreToCount(restoreTranslate);
+        }
+
         // If we created a layer with no content, merge it immediately.
         if (restoreToCount >= 0 && !drewRipples) {
             canvas.restoreToCount(restoreToCount);
@@ -543,11 +611,14 @@
         dirtyBounds.set(drawingBounds);
         drawingBounds.setEmpty();
 
+        final int cX = (int) mHotspotBounds.exactCenterX();
+        final int cY = (int) mHotspotBounds.exactCenterY();
         final Rect rippleBounds = mTempRect;
         final Ripple[] activeRipples = mAnimatingRipples;
         final int N = mAnimatingRipplesCount;
         for (int i = 0; i < N; i++) {
             activeRipples[i].getBounds(rippleBounds);
+            rippleBounds.offset(cX, cY);
             drawingBounds.union(rippleBounds);
         }
 
@@ -563,11 +634,11 @@
 
     static class TouchFeedbackState extends LayerState {
         int[] mTouchThemeAttrs;
-        ColorStateList mTint;
-        PorterDuffXfermode mTintXfermode;
-        PorterDuffXfermode mTintXfermodeInverse;
+        ColorStateList mTint = null;
+        PorterDuffXfermode mTintXfermode = SRC_ATOP;
+        PorterDuffXfermode mTintXfermodeInverse = DST_ATOP;
         Drawable mMask;
-        boolean mPinned;
+        boolean mPinned = false;
 
         public TouchFeedbackState(
                 TouchFeedbackState orig, TouchFeedbackDrawable owner, Resources res) {
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 2da86154..05658f5 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -753,7 +753,7 @@
             }
 
             final TypedArray a = t.resolveAttributes(
-                    mThemeAttrs, R.styleable.VectorDrawablePath, 0, 0);
+                    mThemeAttrs, R.styleable.VectorDrawablePath);
 
             mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
 
diff --git a/graphics/java/android/graphics/pdf/PdfDocument.java b/graphics/java/android/graphics/pdf/PdfDocument.java
index f5b07c1..d603436 100644
--- a/graphics/java/android/graphics/pdf/PdfDocument.java
+++ b/graphics/java/android/graphics/pdf/PdfDocument.java
@@ -32,7 +32,7 @@
 /**
  * <p>
  * This class enables generating a PDF document from native Android content. You
- * open a new document and then for every page you want to add you start a page,
+ * create a new document and then for every page you want to add you start a page,
  * write content to the page, and finish the page. After you are done with all
  * pages, you write the document to an output stream and close the document.
  * After a document is closed you should not use it anymore. Note that pages are
@@ -64,7 +64,7 @@
  * // write the document content
  * document.writeTo(getOutputStream());
  *
- * //close the document
+ * // close the document
  * document.close();
  * </pre>
  */
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
new file mode 100644
index 0000000..3fa3b9f
--- /dev/null
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -0,0 +1,391 @@
+/*
+ * 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.
+ */
+
+package android.graphics.pdf;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+import dalvik.system.CloseGuard;
+import libcore.io.Libcore;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * <p>
+ * This class enables rendering a PDF document. This class is not thread safe.
+ * </p>
+ * <p>
+ * If you want to render a PDF, you create a renderer and for every page you want
+ * to render, you open the page, render it, and close the page. After you are done
+ * with rendering, you close the renderer. After the renderer is closed it should not
+ * be used anymore. Note that the pages are rendered one by one, i.e. you can have
+ * only a single page opened at any given time.
+ * </p>
+ * <p>
+ * A typical use of the APIs to render a PDF looks like this:
+ * </p>
+ * <pre>
+ * // create a new renderer
+ * PdfRenderer renderer = new PdfRenderer(getSeekableFileDescriptor());
+ *
+ * // let us just render all pages
+ * final int pageCount = renderer.getPageCount();
+ * for (int i = 0; i < pageCount; i++) {
+ *     Page page = renderer.openPage(i);
+ *     Bitmap bitmap = getBitmapReuseIfPossible(page);
+ *
+ *     // say we render for showing on the screen
+ *     page.render(bitmap, getContentBoundsInBitmap(),
+ *             getDesiredTransformation(), Page.RENDER_MODE_FOR_DISPLAY);
+ *
+ *     // do stuff with the bitmap
+ *
+ *     renderer.closePage(page);
+ * }
+ *
+ * // close the renderer
+ * renderer.close();
+ * </pre>
+ *
+ * @see #close()
+ */
+public final class PdfRenderer implements AutoCloseable {
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
+    private final Point mTempPoint = new Point();
+
+    private final long mNativeDocument;
+
+    private final int mPageCount;
+
+    private ParcelFileDescriptor mInput;
+
+    private Page mCurrentPage;
+
+    /** @hide */
+    @IntDef({
+        Page.RENDER_MODE_FOR_DISPLAY,
+        Page.RENDER_MODE_FOR_PRINT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RenderMode {}
+
+    /**
+     * Creates a new instance.
+     * <p>
+     * <strong>Note:</strong> The provided file descriptor must be <strong>seekable</strong>,
+     * i.e. its data being randomly accessed, e.g. pointing to a file.
+     * </p>
+     * <p>
+     * <strong>Note:</strong> This class takes ownership of the passed in file descriptor
+     * and is responsible for closing it when the renderer is closed.
+     * </p>
+     *
+     * @param input Seekable file descriptor to read from.
+     */
+    public PdfRenderer(@NonNull ParcelFileDescriptor input) throws IOException {
+        if (input == null) {
+            throw new NullPointerException("input cannot be null");
+        }
+
+        final long size;
+        try {
+            Libcore.os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
+            size = Libcore.os.fstat(input.getFileDescriptor()).st_size;
+        } catch (ErrnoException ee) {
+            throw new IllegalArgumentException("file descriptor not seekable");
+        }
+
+        mInput = input;
+        mNativeDocument = nativeCreate(mInput.getFd(), size);
+        mPageCount = nativeGetPageCount(mNativeDocument);
+        mCloseGuard.open("close");
+    }
+
+    /**
+     * Closes this renderer. You should not use this instance
+     * after this method is called.
+     */
+    public void close() {
+        throwIfClosed();
+        throwIfPageOpened();
+        doClose();
+    }
+
+    /**
+     * Gets the number of pages in the document.
+     *
+     * @return The page count.
+     */
+    public int getPageCount() {
+        throwIfClosed();
+        return mPageCount;
+    }
+
+    /**
+     * Gets whether the document prefers to be scaled for printing.
+     * You should take this info account if the document is rendered
+     * for printing and the target media size differs from the page
+     * size.
+     *
+     * @return If to scale the document.
+     */
+    public boolean shouldScaleForPrinting() {
+        throwIfClosed();
+        return nativeScaleForPrinting(mNativeDocument);
+    }
+
+    /**
+     * Opens a page for rendering.
+     *
+     * @param index The page index.
+     * @return A page that can be rendered.
+     *
+     * @see #closePage(PdfRenderer.Page)
+     */
+    public Page openPage(int index) {
+        throwIfClosed();
+        throwIfPageOpened();
+        mCurrentPage = new Page(index);
+        return mCurrentPage;
+    }
+
+    /**
+     * Closes a page opened for rendering.
+     *
+     * @param page The page to close.
+     *
+     * @see #openPage(int)
+     */
+    public void closePage(@NonNull Page page) {
+        throwIfClosed();
+        throwIfNotCurrentPage(page);
+        throwIfCurrentPageClosed();
+        mCurrentPage.close();
+        mCurrentPage = null;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            mCloseGuard.warnIfOpen();
+            if (mInput != null) {
+                doClose();
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+
+    private void doClose() {
+        if (mCurrentPage != null) {
+            mCurrentPage.close();
+            mCurrentPage = null;
+        }
+        nativeClose(mNativeDocument);
+        try {
+            mInput.close();
+        } catch (IOException ioe) {
+            /* ignore - best effort */
+        }
+        mInput = null;
+        mCloseGuard.close();
+    }
+
+    private void throwIfClosed() {
+        if (mInput == null) {
+            throw new IllegalStateException("Already closed");
+        }
+    }
+
+    private void throwIfPageOpened() {
+        if (mCurrentPage != null) {
+            throw new IllegalStateException("Current page not closed");
+        }
+    }
+
+    private void throwIfCurrentPageClosed() {
+        if (mCurrentPage == null) {
+            throw new IllegalStateException("Already closed");
+        }
+    }
+
+    private void throwIfNotCurrentPage(Page page) {
+        if (page != mCurrentPage) {
+            throw new IllegalArgumentException("Page not from document");
+        }
+    }
+
+    /**
+     * This class represents a PDF document page for rendering.
+     */
+    public final class Page {
+
+        /**
+         * Mode to render the content for display on a screen.
+         */
+        public static final int RENDER_MODE_FOR_DISPLAY = 1;
+
+        /**
+         * Mode to render the content for printing.
+         */
+        public static final int RENDER_MODE_FOR_PRINT = 2;
+
+        private final int mIndex;
+        private final int mWidth;
+        private final int mHeight;
+
+        private long mNativePage;
+
+        private Page(int index) {
+            Point size = mTempPoint;
+            mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
+            mIndex = index;
+            mWidth = size.x;
+            mHeight = size.y;
+        }
+
+        /**
+         * Gets the page index.
+         *
+         * @return The index.
+         */
+        public int getIndex() {
+            return  mIndex;
+        }
+
+        /**
+         * Gets the page width in points (1/72").
+         *
+         * @return The width in points.
+         */
+        public int getWidth() {
+            return mWidth;
+        }
+
+        /**
+         * Gets the page height in points (1/72").
+         *
+         * @return The height in points.
+         */
+        public int getHeight() {
+            return mHeight;
+        }
+
+        /**
+         * Renders a page to a bitmap.
+         * <p>
+         * You may optionally specify a rectangular clip in the bitmap bounds. No rendering
+         * outside the clip will be performed, hence it is your responsibility to initialize
+         * the bitmap outside the clip.
+         * </p>
+         * <p>
+         * You may optionally specify a matrix to transform the content from page coordinates
+         * which are in points (1/72") to bitmap coordintates which are in pixels. If this
+         * matrix is not provided this method will apply a transformation that will fit the
+         * whole page to the destination clip if profided or the destination bitmap if no
+         * clip is provided.
+         * </p>
+         * <p>
+         * The clip and transformation are useful for implementing tile rendering where the
+         * destination bitmap contains a portion of the image, for example when zooming.
+         * Another useful application is for printing where the size of the bitmap holding
+         * the page is too large and a client can render the page in stripes.
+         * </p>
+         * <p>
+         * <strong>Note: </strong> The destination bitmap format must be
+         * {@link Config#ARGB_8888 ARGB}.
+         * </p>
+         * <p>
+         * <strong>Note: </strong> The optional transformation matrix must be affine as per
+         * {@link android.graphics.Matrix#isAffine()}. Hence, you can specify rotation, scaling,
+         * translation but not a perspective transformation.
+         * </p>
+         *
+         * @param destination Destination bitmap to which to render.
+         * @param destClip Optional clip in the bitmap bounds.
+         * @param transform Optional transformation to apply when rendering.
+         * @param renderMode The render mode.
+         *
+         * @see #RENDER_MODE_FOR_DISPLAY
+         * @see #RENDER_MODE_FOR_PRINT
+         */
+        public void render(@NonNull Bitmap destination, @Nullable Rect destClip,
+                           @Nullable Matrix transform, @RenderMode int renderMode) {
+            if (destination.getConfig() != Config.ARGB_8888) {
+                throw new IllegalArgumentException("Unsupported pixel format");
+            }
+
+            if (destClip != null) {
+                if (destClip.left < 0 || destClip.top < 0
+                        || destClip.right > destination.getWidth()
+                        || destClip.bottom > destination.getHeight()) {
+                    throw new IllegalArgumentException("destBounds not in destination");
+                }
+            }
+
+            if (transform != null && !transform.isAffine()) {
+                 throw new IllegalArgumentException("transform not affine");
+            }
+
+            if (renderMode != RENDER_MODE_FOR_PRINT && renderMode != RENDER_MODE_FOR_DISPLAY) {
+                throw new IllegalArgumentException("Unsupported render mode");
+            }
+
+            if (renderMode == RENDER_MODE_FOR_PRINT && renderMode == RENDER_MODE_FOR_DISPLAY) {
+                throw new IllegalArgumentException("Only single render mode supported");
+            }
+
+            final int contentLeft = (destClip != null) ? destClip.left : 0;
+            final int contentTop = (destClip != null) ? destClip.top : 0;
+            final int contentRight = (destClip != null) ? destClip.right
+                    : destination.getWidth();
+            final int contentBottom = (destClip != null) ? destClip.bottom
+                    : destination.getHeight();
+
+            final long transformPtr = (transform != null) ? transform.native_instance : 0;
+
+            nativeRenderPage(mNativeDocument, mNativePage, destination.mNativeBitmap, contentLeft,
+                    contentTop, contentRight, contentBottom, transformPtr, renderMode);
+        }
+
+        void close() {
+            nativeClosePage(mNativePage);
+            mNativePage = 0;
+        }
+    }
+
+    private static native long nativeCreate(int fd, long size);
+    private static native void nativeClose(long documentPtr);
+    private static native int nativeGetPageCount(long documentPtr);
+    private static native boolean nativeScaleForPrinting(long documentPtr);
+    private static native void nativeRenderPage(long documentPtr, long pagePtr, long destPtr,
+            int destLeft, int destTop, int destRight, int destBottom, long matrixPtr, int renderMode);
+    private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex,
+            Point outSize);
+    private static native void nativeClosePage(long pagePtr);
+}
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index a033f86..b80f7e9 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -27,31 +27,64 @@
 namespace uirenderer {
 
 /************************************************************
- *  Base animator
+ *  BaseRenderNodeAnimator
  ************************************************************/
 
-BaseAnimator::BaseAnimator()
-        : mInterpolator(0)
-        , mPlayState(PENDING)
+BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
+        : mFinalValue(finalValue)
+        , mDeltaValue(0)
+        , mFromValue(0)
+        , mInterpolator(0)
+        , mPlayState(NEEDS_START)
         , mStartTime(0)
-        , mDuration(300) {
+        , mDelayUntil(0)
+        , mDuration(300)
+        , mStartDelay(0) {
 
 }
 
-BaseAnimator::~BaseAnimator() {
+BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
     setInterpolator(NULL);
 }
 
-void BaseAnimator::setInterpolator(Interpolator* interpolator) {
+void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
     delete mInterpolator;
     mInterpolator = interpolator;
 }
 
-void BaseAnimator::setDuration(nsecs_t duration) {
+void BaseRenderNodeAnimator::setStartValue(float value) {
+    LOG_ALWAYS_FATAL_IF(mPlayState != NEEDS_START,
+            "Cannot set the start value after the animator has started!");
+    mFromValue = value;
+    mDeltaValue = (mFinalValue - mFromValue);
+    mPlayState = PENDING;
+}
+
+void BaseRenderNodeAnimator::setupStartValueIfNecessary(RenderNode* target, TreeInfo& info) {
+    if (mPlayState == NEEDS_START) {
+        setStartValue(getValue(target));
+        mPlayState = PENDING;
+    }
+}
+
+void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
     mDuration = duration;
 }
 
-bool BaseAnimator::animateFrame(TreeInfo& info) {
+void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) {
+    mStartDelay = startDelay;
+}
+
+bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
+    if (mPlayState == PENDING && mStartDelay > 0 && mDelayUntil == 0) {
+        mDelayUntil = info.frameTimeMs + mStartDelay;
+        return false;
+    }
+
+    if (mDelayUntil > info.frameTimeMs) {
+        return false;
+    }
+
     if (mPlayState == PENDING) {
         mPlayState = RUNNING;
         mStartTime = info.frameTimeMs;
@@ -59,7 +92,6 @@
         if (!mInterpolator) {
             setInterpolator(Interpolator::createDefaultInterpolator());
         }
-        onAnimationStarted();
     }
 
     float fraction = 1.0f;
@@ -71,17 +103,16 @@
         }
     }
     fraction = mInterpolator->interpolate(fraction);
-    onAnimationUpdated(fraction);
+    setValue(target, mFromValue + (mDeltaValue * fraction));
 
     if (mPlayState == FINISHED) {
-        onAnimationFinished();
         callOnFinishedListener(info);
         return true;
     }
     return false;
 }
 
-void BaseAnimator::callOnFinishedListener(TreeInfo& info) {
+void BaseRenderNodeAnimator::callOnFinishedListener(TreeInfo& info) {
     if (mListener.get()) {
         if (!info.animationHook) {
             mListener->onAnimationFinished(this);
@@ -92,70 +123,49 @@
 }
 
 /************************************************************
- *  BaseRenderNodeAnimator
- ************************************************************/
-
-BaseRenderNodeAnimator::BaseRenderNodeAnimator(
-                BaseRenderNodeAnimator::DeltaValueType deltaType, float delta)
-        : mTarget(0)
-        , mDeltaValueType(deltaType)
-        , mDeltaValue(delta)
-        , mFromValue(-1) {
-}
-
-bool BaseRenderNodeAnimator::animate(RenderNode* target, TreeInfo& info) {
-    mTarget = target;
-    bool finished = animateFrame(info);
-    mTarget = NULL;
-    return finished;
-}
-
-void BaseRenderNodeAnimator::onAnimationStarted() {
-    mFromValue = getValue();
-
-    if (mDeltaValueType == BaseRenderNodeAnimator::ABSOLUTE) {
-        mDeltaValue = (mDeltaValue - mFromValue);
-        mDeltaValueType = BaseRenderNodeAnimator::DELTA;
-    }
-}
-
-void BaseRenderNodeAnimator::onAnimationUpdated(float fraction) {
-    float value = mFromValue + (mDeltaValue * fraction);
-    setValue(value);
-}
-
-/************************************************************
  *  RenderPropertyAnimator
  ************************************************************/
 
-// Maps RenderProperty enum to accessors
-const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
-    {&RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
-    {&RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
-    {&RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
-    {&RenderProperties::getScaleX, &RenderProperties::setScaleX },
-    {&RenderProperties::getScaleY, &RenderProperties::setScaleY },
-    {&RenderProperties::getRotation, &RenderProperties::setRotation },
-    {&RenderProperties::getRotationX, &RenderProperties::setRotationX },
-    {&RenderProperties::getRotationY, &RenderProperties::setRotationY },
-    {&RenderProperties::getX, &RenderProperties::setX },
-    {&RenderProperties::getY, &RenderProperties::setY },
-    {&RenderProperties::getZ, &RenderProperties::setZ },
-    {&RenderProperties::getAlpha, &RenderProperties::setAlpha },
+struct RenderPropertyAnimator::PropertyAccessors {
+   RenderNode::DirtyPropertyMask dirtyMask;
+   GetFloatProperty getter;
+   SetFloatProperty setter;
 };
 
-RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property,
-                DeltaValueType deltaType, float deltaValue)
-        : BaseRenderNodeAnimator(deltaType, deltaValue)
-        , mPropertyAccess(PROPERTY_ACCESSOR_LUT[property]) {
+// Maps RenderProperty enum to accessors
+const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
+    {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
+    {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
+    {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
+    {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX },
+    {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY },
+    {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation },
+    {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX },
+    {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY },
+    {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX },
+    {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY },
+    {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ },
+    {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha },
+};
+
+RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
+        : BaseRenderNodeAnimator(finalValue)
+        , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {
 }
 
-float RenderPropertyAnimator::getValue() const {
-    return (target()->animatorProperties().*mPropertyAccess.getter)();
+void RenderPropertyAnimator::onAttached(RenderNode* target) {
+    if (target->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
+        setStartValue((target->stagingProperties().*mPropertyAccess->getter)());
+    }
+    (target->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
 }
 
-void RenderPropertyAnimator::setValue(float value) {
-    (target()->animatorProperties().*mPropertyAccess.setter)(value);
+float RenderPropertyAnimator::getValue(RenderNode* target) const {
+    return (target->properties().*mPropertyAccess->getter)();
+}
+
+void RenderPropertyAnimator::setValue(RenderNode* target, float value) {
+    (target->animatorProperties().*mPropertyAccess->setter)(value);
 }
 
 /************************************************************
@@ -163,16 +173,16 @@
  ************************************************************/
 
 CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
-                CanvasPropertyPrimitive* property, DeltaValueType deltaType, float deltaValue)
-        : BaseRenderNodeAnimator(deltaType, deltaValue)
+                CanvasPropertyPrimitive* property, float finalValue)
+        : BaseRenderNodeAnimator(finalValue)
         , mProperty(property) {
 }
 
-float CanvasPropertyPrimitiveAnimator::getValue() const {
+float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
     return mProperty->value;
 }
 
-void CanvasPropertyPrimitiveAnimator::setValue(float value) {
+void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) {
     mProperty->value = value;
 }
 
@@ -181,14 +191,13 @@
  ************************************************************/
 
 CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
-                CanvasPropertyPaint* property, PaintField field,
-                DeltaValueType deltaType, float deltaValue)
-        : BaseRenderNodeAnimator(deltaType, deltaValue)
+                CanvasPropertyPaint* property, PaintField field, float finalValue)
+        : BaseRenderNodeAnimator(finalValue)
         , mProperty(property)
         , mField(field) {
 }
 
-float CanvasPropertyPaintAnimator::getValue() const {
+float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const {
     switch (mField) {
     case STROKE_WIDTH:
         return mProperty->value.getStrokeWidth();
@@ -204,7 +213,7 @@
     return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c );
 }
 
-void CanvasPropertyPaintAnimator::setValue(float value) {
+void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) {
     switch (mField) {
     case STROKE_WIDTH:
         mProperty->value.setStrokeWidth(value);
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 52a1807..7741617 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -33,90 +33,63 @@
 
 class AnimationListener : public VirtualLightRefBase {
 public:
-    ANDROID_API virtual void onAnimationFinished(BaseAnimator*) = 0;
+    ANDROID_API virtual void onAnimationFinished(BaseRenderNodeAnimator*) = 0;
 protected:
     ANDROID_API virtual ~AnimationListener() {}
 };
 
-// Helper class to contain generic animator helpers
-class BaseAnimator : public VirtualLightRefBase {
-    PREVENT_COPY_AND_ASSIGN(BaseAnimator);
+class BaseRenderNodeAnimator : public VirtualLightRefBase {
+    PREVENT_COPY_AND_ASSIGN(BaseRenderNodeAnimator);
 public:
-
     ANDROID_API void setInterpolator(Interpolator* interpolator);
     ANDROID_API void setDuration(nsecs_t durationInMs);
     ANDROID_API nsecs_t duration() { return mDuration; }
+    ANDROID_API void setStartDelay(nsecs_t startDelayInMs);
+    ANDROID_API nsecs_t startDelay() { return mStartDelay; }
     ANDROID_API void setListener(AnimationListener* listener) {
         mListener = listener;
     }
 
+    ANDROID_API virtual void onAttached(RenderNode* target) {}
+
+    // Guaranteed to happen before the staging push
+    void setupStartValueIfNecessary(RenderNode* target, TreeInfo& info);
+
+    bool animate(RenderNode* target, TreeInfo& info);
+
     bool isFinished() { return mPlayState == FINISHED; }
+    float finalValue() { return mFinalValue; }
 
 protected:
-    BaseAnimator();
-    virtual ~BaseAnimator();
+    BaseRenderNodeAnimator(float finalValue);
+    virtual ~BaseRenderNodeAnimator();
 
-    // This is the main animation entrypoint that subclasses should call
-    // to generate the onAnimation* lifecycle events
-    // Returns true if the animation has finished, false otherwise
-    bool animateFrame(TreeInfo& info);
-
-    // Called when PlayState switches from PENDING to RUNNING
-    virtual void onAnimationStarted() {}
-    virtual void onAnimationUpdated(float fraction) = 0;
-    virtual void onAnimationFinished() {}
+    void setStartValue(float value);
+    virtual float getValue(RenderNode* target) const = 0;
+    virtual void setValue(RenderNode* target, float value) = 0;
 
 private:
     void callOnFinishedListener(TreeInfo& info);
 
     enum PlayState {
+        NEEDS_START,
         PENDING,
         RUNNING,
         FINISHED,
     };
 
-    Interpolator* mInterpolator;
-    PlayState mPlayState;
-    long mStartTime;
-    long mDuration;
-
-   sp<AnimationListener> mListener;
-};
-
-class BaseRenderNodeAnimator : public BaseAnimator {
-public:
-    // Since the UI thread doesn't necessarily know what the current values
-    // actually are and thus can't do the calculations, this is used to inform
-    // the animator how to lazy-resolve the input value
-    enum DeltaValueType {
-        // The delta value represents an absolute value endpoint
-        // mDeltaValue needs to be recalculated to be mDelta = (mDelta - fromValue)
-        // in onAnimationStarted()
-        ABSOLUTE = 0,
-        // The final value represents an offset from the current value
-        // No recalculation is needed
-        DELTA,
-    };
-
-    bool animate(RenderNode* target, TreeInfo& info);
-
-protected:
-    BaseRenderNodeAnimator(DeltaValueType deltaType, float deltaValue);
-
-    RenderNode* target() const { return mTarget; }
-    virtual float getValue() const = 0;
-    virtual void setValue(float value) = 0;
-
-private:
-    virtual void onAnimationStarted();
-    virtual void onAnimationUpdated(float fraction);
-
-    // mTarget is only valid inside animate()
-    RenderNode* mTarget;
-
-    BaseRenderNodeAnimator::DeltaValueType mDeltaValueType;
+    float mFinalValue;
     float mDeltaValue;
     float mFromValue;
+
+    Interpolator* mInterpolator;
+    PlayState mPlayState;
+    nsecs_t mStartTime;
+    nsecs_t mDelayUntil;
+    nsecs_t mDuration;
+    nsecs_t mStartDelay;
+
+    sp<AnimationListener> mListener;
 };
 
 class RenderPropertyAnimator : public BaseRenderNodeAnimator {
@@ -136,23 +109,20 @@
         ALPHA,
     };
 
-    ANDROID_API RenderPropertyAnimator(RenderProperty property,
-                DeltaValueType deltaType, float deltaValue);
+    ANDROID_API RenderPropertyAnimator(RenderProperty property, float finalValue);
+
+    ANDROID_API virtual void onAttached(RenderNode* target);
 
 protected:
-    ANDROID_API virtual float getValue() const;
-    ANDROID_API virtual void setValue(float value);
+    virtual float getValue(RenderNode* target) const;
+    virtual void setValue(RenderNode* target, float value);
 
 private:
     typedef void (RenderProperties::*SetFloatProperty)(float value);
     typedef float (RenderProperties::*GetFloatProperty)() const;
 
-    struct PropertyAccessors {
-        GetFloatProperty getter;
-        SetFloatProperty setter;
-    };
-
-    PropertyAccessors mPropertyAccess;
+    struct PropertyAccessors;
+    const PropertyAccessors* mPropertyAccess;
 
     static const PropertyAccessors PROPERTY_ACCESSOR_LUT[];
 };
@@ -160,10 +130,10 @@
 class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator {
 public:
     ANDROID_API CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
-            DeltaValueType deltaType, float deltaValue);
+            float finalValue);
 protected:
-    ANDROID_API virtual float getValue() const;
-    ANDROID_API virtual void setValue(float value);
+    virtual float getValue(RenderNode* target) const;
+    virtual void setValue(RenderNode* target, float value);
 private:
     sp<CanvasPropertyPrimitive> mProperty;
 };
@@ -176,10 +146,10 @@
     };
 
     ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
-            PaintField field, DeltaValueType deltaType, float deltaValue);
+            PaintField field, float finalValue);
 protected:
-    ANDROID_API virtual float getValue() const;
-    ANDROID_API virtual void setValue(float value);
+    virtual float getValue(RenderNode* target) const;
+    virtual void setValue(RenderNode* target, float value);
 private:
     sp<CanvasPropertyPaint> mProperty;
     PaintField mField;
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 45b6624..3016814 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -28,6 +28,7 @@
 #include "DeferredDisplayList.h"
 #include "DisplayListOp.h"
 #include "OpenGLRenderer.h"
+#include "utils/MathUtils.h"
 
 #if DEBUG_DEFER
     #define DEFER_LOGD(...) ALOGD(__VA_ARGS__)
@@ -146,10 +147,6 @@
     mergeid_t mMergeId;
 };
 
-// compare alphas approximately, with a small margin
-#define NEQ_FALPHA(lhs, rhs) \
-        fabs((float)lhs - (float)rhs) > 0.001f
-
 class MergingDrawBatch : public DrawBatch {
 public:
     MergingDrawBatch(DeferInfo& deferInfo, int width, int height) :
@@ -196,7 +193,11 @@
         const DeferredDisplayState* lhs = state;
         const DeferredDisplayState* rhs = mOps[0].state;
 
-        if (NEQ_FALPHA(lhs->mAlpha, rhs->mAlpha)) return false;
+        if (!MathUtils::areEqual(lhs->mAlpha, rhs->mAlpha)) return false;
+
+        // Identical round rect clip state means both ops will clip in the same way, or not at all.
+        // As the state objects are const, we can compare their pointers to determine mergeability
+        if (lhs->mRoundRectClipState != rhs->mRoundRectClipState) return false;
 
         /* Clipping compatibility check
          *
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index fca3588..48489c2 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -64,6 +64,7 @@
     mat4 mMatrix;
     DrawModifiers mDrawModifiers;
     float mAlpha;
+    const RoundRectClipState* mRoundRectClipState;
 };
 
 class OpStatePair {
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 4df97e6..7993c0f 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -711,6 +711,7 @@
             mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
             mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
             mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
+            mSnapshot->roundRectClipState = NULL;
         }
     }
 
@@ -844,6 +845,7 @@
     mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
     mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
     mSnapshot->initializeViewport(bounds.getWidth(), bounds.getHeight());
+    mSnapshot->roundRectClipState = NULL;
 
     endTiling();
     debugOverdraw(false, false);
@@ -872,8 +874,6 @@
 
     // Change the ortho projection
     glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
-
-
     return true;
 }
 
@@ -892,7 +892,7 @@
 
     bool clipRequired = false;
     calculateQuickRejectForScissor(rect.left, rect.top, rect.right, rect.bottom,
-            &clipRequired, false); // safely ignore return, should never be rejected
+            &clipRequired, NULL, false); // safely ignore return, should never be rejected
     mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
 
     if (fboLayer) {
@@ -1367,6 +1367,9 @@
     state.mMatrix.load(*currentMatrix);
     state.mDrawModifiers = mDrawModifiers;
     state.mAlpha = currentSnapshot()->alpha;
+
+    // always store/restore, since it's just a pointer
+    state.mRoundRectClipState = currentSnapshot()->roundRectClipState;
     return false;
 }
 
@@ -1374,6 +1377,7 @@
     setMatrix(state.mMatrix);
     mSnapshot->alpha = state.mAlpha;
     mDrawModifiers = state.mDrawModifiers;
+    mSnapshot->roundRectClipState = state.mRoundRectClipState;
 
     if (state.mClipValid && !skipClipRestore) {
         mSnapshot->setClip(state.mClip.left, state.mClip.top,
@@ -1449,7 +1453,7 @@
 
             mCaches.stencil.enableWrite();
 
-            // Clear the stencil but first make sure we restrict drawing
+            // Clear and update the stencil, but first make sure we restrict drawing
             // to the region's bounds
             bool resetScissor = mCaches.enableScissor();
             if (resetScissor) {
@@ -1457,7 +1461,10 @@
                 setScissorFromClip();
             }
             mCaches.stencil.clear();
-            if (resetScissor) mCaches.disableScissor();
+
+            // stash and disable the outline clip state, since stencil doesn't account for outline
+            bool storedSkipOutlineClip = mSkipOutlineClip;
+            mSkipOutlineClip = true;
 
             SkPaint paint;
             paint.setColor(0xff000000);
@@ -1470,6 +1477,8 @@
             // The last parameter is important: we are not drawing in the color buffer
             // so we don't want to dirty the current layer, if any
             drawRegionRects(*(currentSnapshot()->clipRegion), paint, false);
+            if (resetScissor) mCaches.disableScissor();
+            mSkipOutlineClip = storedSkipOutlineClip;
 
             mCaches.stencil.enableTest();
 
@@ -1494,7 +1503,6 @@
  */
 bool OpenGLRenderer::quickRejectSetupScissor(float left, float top, float right, float bottom,
         const SkPaint* paint) {
-    bool clipRequired = false;
     bool snapOut = paint && paint->isAntiAlias();
 
     if (paint && paint->getStyle() != SkPaint::kFill_Style) {
@@ -1505,13 +1513,17 @@
         bottom += outset;
     }
 
-    if (calculateQuickRejectForScissor(left, top, right, bottom, &clipRequired, snapOut)) {
+    bool clipRequired = false;
+    bool roundRectClipRequired = false;
+    if (calculateQuickRejectForScissor(left, top, right, bottom,
+            &clipRequired, &roundRectClipRequired, snapOut)) {
         return true;
     }
 
     if (!isRecording()) {
         // not quick rejected, so enable the scissor if clipRequired
         mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
+        mSkipOutlineClip = !roundRectClipRequired;
     }
     return false;
 }
@@ -1668,6 +1680,18 @@
 
 void OpenGLRenderer::setupDrawProgram() {
     useProgram(mCaches.programCache.get(mDescription));
+    if (mDescription.hasRoundRectClip) {
+        // TODO: avoid doing this repeatedly, stashing state pointer in program
+        const RoundRectClipState* state = mSnapshot->roundRectClipState;
+        const Rect& innerRect = state->outlineInnerRect;
+        glUniform4f(mCaches.currentProgram->getUniform("roundRectInnerRectLTRB"),
+                innerRect.left,  innerRect.top,
+                innerRect.right,  innerRect.bottom);
+        glUniform1f(mCaches.currentProgram->getUniform("roundRectRadius"),
+                state->outlineRadius);
+        glUniformMatrix4fv(mCaches.currentProgram->getUniform("roundRectInvTransform"),
+                1, GL_FALSE, &state->matrix.data[0]);
+    }
 }
 
 void OpenGLRenderer::setupDrawDirtyRegionsDisabled() {
@@ -2902,7 +2926,7 @@
 
     bool clipRequired = false;
     const bool rejected = calculateQuickRejectForScissor(x, y,
-            x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, false);
+            x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired, NULL, false);
 
     if (rejected) {
         if (transform && !transform->isIdentity()) {
@@ -3433,6 +3457,13 @@
 
 void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
         ProgramDescription& description, bool swapSrcDst) {
+
+    if (mSnapshot->roundRectClipState != NULL /*&& !mSkipOutlineClip*/) {
+        blend = true;
+        mDescription.hasRoundRectClip = true;
+    }
+    mSkipOutlineClip = true;
+
     if (mCountOverdraw) {
         if (!mCaches.blend) glEnable(GL_BLEND);
         if (mCaches.lastSrcMode != GL_ONE || mCaches.lastDstMode != GL_ONE) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index b58b817..f70ae58 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -993,6 +993,8 @@
     bool mCountOverdraw;
     float mOverdraw;
 
+    bool mSkipOutlineClip;
+
     friend class DisplayListRenderer;
     friend class Layer;
     friend class TextSetupFunctor;
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index 530be30..5c24335 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -58,11 +58,24 @@
         mShouldClip = clip;
     }
 
+    bool getShouldClip() const {
+        return mShouldClip;
+    }
+
     bool willClip() const {
         // only round rect outlines can be used for clipping
         return mShouldClip && (mType == kOutlineType_RoundRect);
     }
 
+    bool getAsRoundRect(Rect* outRect, float* outRadius) const {
+        if (mType == kOutlineType_RoundRect) {
+            outRect->set(mBounds);
+            *outRadius = mRadius;
+            return true;
+        }
+        return false;
+    }
+
     const SkPath* getPath() const {
         if (mType == kOutlineType_None) return NULL;
 
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 33c91b3..3e191d0 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -45,17 +45,18 @@
 #define COLOR_COMPONENT_THRESHOLD 1.0f
 #define COLOR_COMPONENT_INV_THRESHOLD 0.0f
 
-#define PROGRAM_KEY_TEXTURE 0x1
-#define PROGRAM_KEY_A8_TEXTURE 0x2
-#define PROGRAM_KEY_BITMAP 0x4
-#define PROGRAM_KEY_GRADIENT 0x8
-#define PROGRAM_KEY_BITMAP_FIRST 0x10
-#define PROGRAM_KEY_COLOR_MATRIX 0x20
-#define PROGRAM_KEY_COLOR_BLEND 0x40
-#define PROGRAM_KEY_BITMAP_NPOT 0x80
-#define PROGRAM_KEY_SWAP_SRC_DST 0x2000
+#define PROGRAM_KEY_TEXTURE             0x01
+#define PROGRAM_KEY_A8_TEXTURE          0x02
+#define PROGRAM_KEY_BITMAP              0x04
+#define PROGRAM_KEY_GRADIENT            0x08
+#define PROGRAM_KEY_BITMAP_FIRST        0x10
+#define PROGRAM_KEY_COLOR_MATRIX        0x20
+#define PROGRAM_KEY_COLOR_BLEND         0x40
+#define PROGRAM_KEY_BITMAP_NPOT         0x80
 
-#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
+#define PROGRAM_KEY_SWAP_SRC_DST      0x2000
+
+#define PROGRAM_KEY_BITMAP_WRAPS_MASK  0x600
 #define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
 
 // Encode the xfermodes on 6 bits
@@ -83,6 +84,7 @@
 
 #define PROGRAM_HAS_DEBUG_HIGHLIGHT 42
 #define PROGRAM_EMULATE_STENCIL 43
+#define PROGRAM_HAS_ROUND_RECT_CLIP 44
 
 ///////////////////////////////////////////////////////////////////////////////
 // Types
@@ -158,6 +160,7 @@
 
     bool hasDebugHighlight;
     bool emulateStencil;
+    bool hasRoundRectClip;
 
     /**
      * Resets this description. All fields are reset back to the default
@@ -198,6 +201,8 @@
         gamma = 2.2f;
 
         hasDebugHighlight = false;
+        emulateStencil = false;
+        hasRoundRectClip = false;
     }
 
     /**
@@ -264,6 +269,7 @@
         if (hasColors) key |= programid(0x1) << PROGRAM_HAS_COLORS;
         if (hasDebugHighlight) key |= programid(0x1) << PROGRAM_HAS_DEBUG_HIGHLIGHT;
         if (emulateStencil) key |= programid(0x1) << PROGRAM_EMULATE_STENCIL;
+        if (hasRoundRectClip) key |= programid(0x1) << PROGRAM_HAS_ROUND_RECT_CLIP;
         return key;
     }
 
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 6d50410..f451690 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -58,6 +58,8 @@
 const char* gVS_Header_Uniforms_HasBitmap =
         "uniform mat4 textureTransform;\n"
         "uniform mediump vec2 textureDimension;\n";
+const char* gVS_Header_Uniforms_HasRoundRectClip =
+        "uniform mat4 roundRectInvTransform;\n";
 const char* gVS_Header_Varyings_HasTexture =
         "varying vec2 outTexCoords;\n";
 const char* gVS_Header_Varyings_HasColors =
@@ -85,6 +87,8 @@
         "varying highp vec2 sweep;\n"
         "varying vec2 ditherTexCoords;\n",
 };
+const char* gVS_Header_Varyings_HasRoundRectClip =
+        "varying vec2 roundRectPos;\n";
 const char* gVS_Main =
         "\nvoid main(void) {\n";
 const char* gVS_Main_OutTexCoords =
@@ -115,9 +119,12 @@
 const char* gVS_Main_OutBitmapTexCoords =
         "    outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
 const char* gVS_Main_Position =
-        "    gl_Position = projection * transform * position;\n";
+        "    vec4 transformedPosition = projection * transform * position;\n"
+        "    gl_Position = transformedPosition;\n";
 const char* gVS_Main_AAVertexShape =
         "    alpha = vtxAlpha;\n";
+const char* gVS_Main_HasRoundRectClip =
+        "    roundRectPos = (roundRectInvTransform * transformedPosition).xy;\n";
 const char* gVS_Footer =
         "}\n\n";
 
@@ -160,6 +167,10 @@
 const char* gFS_Uniforms_Gamma =
         "uniform float gamma;\n";
 
+const char* gFS_Uniforms_HasRoundRectClip =
+        "uniform vec4 roundRectInnerRectLTRB;\n"
+        "uniform float roundRectRadius;\n";
+
 const char* gFS_Main =
         "\nvoid main(void) {\n"
         "    lowp vec4 fragColor;\n";
@@ -318,6 +329,15 @@
         // PorterDuff
         "    fragColor = blendColors(colorBlend, fragColor);\n"
 };
+
+// Note: LTRB -> xyzw
+const char* gFS_Main_FragColor_HasRoundRectClip =
+        "    mediump vec2 fragToLT = roundRectInnerRectLTRB.xy - roundRectPos;\n"
+        "    mediump vec2 fragFromRB = roundRectPos - roundRectInnerRectLTRB.zw;\n"
+        "    mediump vec2 dist = max(max(fragToLT, fragFromRB), vec2(0.0, 0.0));\n"
+        "    mediump float linearDist = roundRectRadius - length(dist);\n"
+        "    gl_FragColor *= clamp(linearDist, 0.0, 1.0);\n";
+
 const char* gFS_Main_DebugHighlight =
         "    gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n";
 const char* gFS_Main_EmulateStencil =
@@ -462,6 +482,9 @@
     if (description.hasBitmap) {
         shader.append(gVS_Header_Uniforms_HasBitmap);
     }
+    if (description.hasRoundRectClip) {
+        shader.append(gVS_Header_Uniforms_HasRoundRectClip);
+    }
     // Varyings
     if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Varyings_HasTexture);
@@ -478,6 +501,9 @@
     if (description.hasBitmap) {
         shader.append(gVS_Header_Varyings_HasBitmap);
     }
+    if (description.hasRoundRectClip) {
+        shader.append(gVS_Header_Varyings_HasRoundRectClip);
+    }
 
     // Begin the shader
     shader.append(gVS_Main); {
@@ -500,6 +526,9 @@
         if (description.hasGradient) {
             shader.append(gVS_Main_OutGradient[gradientIndex(description)]);
         }
+        if (description.hasRoundRectClip) {
+            shader.append(gVS_Main_HasRoundRectClip);
+        }
     }
     // End the shader
     shader.append(gVS_Footer);
@@ -546,6 +575,9 @@
     if (description.hasBitmap) {
         shader.append(gVS_Header_Varyings_HasBitmap);
     }
+    if (description.hasRoundRectClip) {
+        shader.append(gVS_Header_Varyings_HasRoundRectClip);
+    }
 
     // Uniforms
     int modulateOp = MODULATE_OP_NO_MODULATE;
@@ -568,11 +600,18 @@
     if (description.hasGammaCorrection) {
         shader.append(gFS_Uniforms_Gamma);
     }
+    if (description.hasRoundRectClip) {
+        shader.append(gFS_Uniforms_HasRoundRectClip);
+    }
 
     // Optimization for common cases
-    if (!description.isAA && !blendFramebuffer && !description.hasColors &&
-            description.colorOp == ProgramDescription::kColorNone &&
-            !description.hasDebugHighlight && !description.emulateStencil) {
+    if (!description.isAA
+            && !blendFramebuffer
+            && !description.hasColors
+            && description.colorOp == ProgramDescription::kColorNone
+            && !description.hasDebugHighlight
+            && !description.emulateStencil
+            && !description.hasRoundRectClip) {
         bool fast = false;
 
         const bool noShader = !description.hasGradient && !description.hasBitmap;
@@ -722,6 +761,9 @@
         if (description.hasColors) {
             shader.append(gFS_Main_FragColor_HasColors);
         }
+        if (description.hasRoundRectClip) {
+            shader.append(gFS_Main_FragColor_HasRoundRectClip);
+        }
         if (description.hasDebugHighlight) {
             shader.append(gFS_Main_DebugHighlight);
         }
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index f38d8b7..2ddbbd7 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -234,7 +234,7 @@
         bottom = ceilf(bottom);
     }
 
-    void dump(const char* label) const {
+    void dump(const char* label = NULL) const {
         ALOGD("%s[l=%f t=%f r=%f b=%f]", label ? label : "Rect", left, top, right, bottom);
     }
 
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index fba482d..f0645a9 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -53,7 +53,7 @@
 }
 
 RenderNode::RenderNode()
-        : mNeedsPropertiesSync(false)
+        : mDirtyPropertyFields(0)
         , mNeedsDisplayListDataSync(false)
         , mDisplayListData(0)
         , mStagingDisplayListData(0)
@@ -109,23 +109,37 @@
     prepareSubTree(info, mDisplayListData);
 }
 
-static bool is_finished(const sp<BaseRenderNodeAnimator>& animator) {
-    return animator->isFinished();
-}
+class PushAnimatorsFunctor {
+public:
+    PushAnimatorsFunctor(RenderNode* target, TreeInfo& info)
+            : mTarget(target), mInfo(info) {}
+
+    bool operator() (const sp<BaseRenderNodeAnimator>& animator) {
+        animator->setupStartValueIfNecessary(mTarget, mInfo);
+        return animator->isFinished();
+    }
+private:
+    RenderNode* mTarget;
+    TreeInfo& mInfo;
+};
 
 void RenderNode::pushStagingChanges(TreeInfo& info) {
-    if (mNeedsPropertiesSync) {
-        mNeedsPropertiesSync = false;
-        mProperties = mStagingProperties;
-    }
+    // Push the animators first so that setupStartValueIfNecessary() is called
+    // before properties() is trampled by stagingProperties(), as they are
+    // required by some animators.
     if (mNeedsAnimatorsSync) {
         mAnimators.resize(mStagingAnimators.size());
         std::vector< sp<BaseRenderNodeAnimator> >::iterator it;
+        PushAnimatorsFunctor functor(this, info);
         // hint: this means copy_if_not()
         it = std::remove_copy_if(mStagingAnimators.begin(), mStagingAnimators.end(),
-                mAnimators.begin(), is_finished);
+                mAnimators.begin(), functor);
         mAnimators.resize(std::distance(mAnimators.begin(), it));
     }
+    if (mDirtyPropertyFields) {
+        mDirtyPropertyFields = 0;
+        mProperties = mStagingProperties;
+    }
     if (mNeedsDisplayListDataSync) {
         mNeedsDisplayListDataSync = false;
         // Do a push pass on the old tree to handle freeing DisplayListData
@@ -144,7 +158,7 @@
     AnimateFunctor(RenderNode* target, TreeInfo& info)
             : mTarget(target), mInfo(info) {}
 
-    bool operator() (sp<BaseRenderNodeAnimator>& animator) {
+    bool operator() (const sp<BaseRenderNodeAnimator>& animator) {
         return animator->animate(mTarget, mInfo);
     }
 private:
@@ -653,6 +667,10 @@
     bool quickRejected = properties().getClipToBounds()
             && renderer.quickRejectConservative(0, 0, properties().getWidth(), properties().getHeight());
     if (!quickRejected) {
+        if (mProperties.getOutline().willClip()) {
+            renderer.setClippingOutline(alloc, &(mProperties.getOutline()));
+        }
+
         Vector<ZDrawDisplayListOpPair> zTranslatedNodes;
         buildZSortedChildList(zTranslatedNodes);
 
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index bc62ee1..1811a7b 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -82,6 +82,22 @@
  */
 class RenderNode : public VirtualLightRefBase {
 public:
+    enum DirtyPropertyMask {
+        GENERIC         = 1 << 1,
+        TRANSLATION_X   = 1 << 2,
+        TRANSLATION_Y   = 1 << 3,
+        TRANSLATION_Z   = 1 << 4,
+        SCALE_X         = 1 << 5,
+        SCALE_Y         = 1 << 6,
+        ROTATION        = 1 << 7,
+        ROTATION_X      = 1 << 8,
+        ROTATION_Y      = 1 << 9,
+        X               = 1 << 10,
+        Y               = 1 << 11,
+        Z               = 1 << 12,
+        ALPHA           = 1 << 13,
+    };
+
     ANDROID_API RenderNode();
     ANDROID_API virtual ~RenderNode();
 
@@ -123,6 +139,14 @@
         }
     }
 
+    bool isPropertyFieldDirty(DirtyPropertyMask field) const {
+        return mDirtyPropertyFields & field;
+    }
+
+    void setPropertyFieldsDirty(uint32_t fields) {
+        mDirtyPropertyFields |= fields;
+    }
+
     const RenderProperties& properties() {
         return mProperties;
     }
@@ -136,7 +160,6 @@
     }
 
     RenderProperties& mutateStagingProperties() {
-        mNeedsPropertiesSync = true;
         return mStagingProperties;
     }
 
@@ -152,6 +175,7 @@
 
     // UI thread only!
     ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
+        animator->onAttached(this);
         mStagingAnimators.insert(animator);
         mNeedsAnimatorsSync = true;
     }
@@ -227,7 +251,7 @@
 
     String8 mName;
 
-    bool mNeedsPropertiesSync;
+    uint32_t mDirtyPropertyFields;
     RenderProperties mProperties;
     RenderProperties mStagingProperties;
 
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 029b56d..80f7eca 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -20,6 +20,8 @@
 
 #include <SkCanvas.h>
 
+#include "utils/MathUtils.h"
+
 namespace android {
 namespace uirenderer {
 
@@ -34,7 +36,8 @@
         , fbo(0)
         , invisible(false)
         , empty(false)
-        , alpha(1.0f) {
+        , alpha(1.0f)
+        , roundRectClipState(NULL) {
     transform = &mTransformRoot;
     clipRect = &mClipRectRoot;
     region = NULL;
@@ -53,8 +56,8 @@
         , invisible(s->invisible)
         , empty(false)
         , alpha(s->alpha)
+        , roundRectClipState(s->roundRectClipState)
         , mViewportData(s->mViewportData) {
-
     if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
         mTransformRoot.load(*s->transform);
         transform = &mTransformRoot;
@@ -204,6 +207,49 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+// Clipping outline
+///////////////////////////////////////////////////////////////////////////////
+
+void Snapshot::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
+    Rect bounds;
+    float radius;
+    if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
+
+    if (!MathUtils::isPositive(radius)) return; // leave clipping up to rect clipping
+
+    RoundRectClipState* state = new (allocator) RoundRectClipState;
+
+    // store the inverse drawing matrix
+    Matrix4 outlineDrawingMatrix;
+    outlineDrawingMatrix.load(getOrthoMatrix());
+    outlineDrawingMatrix.multiply(*transform);
+    state->matrix.loadInverse(outlineDrawingMatrix);
+
+    // compute area under rounded corners - only draws overlapping these rects need to be clipped
+    for (int i = 0 ; i < 4; i++) {
+        state->dangerRects[i] = bounds;
+    }
+    state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius;
+    state->dangerRects[0].right = state->dangerRects[2].right = bounds.left + radius;
+    state->dangerRects[1].left = state->dangerRects[3].left = bounds.right - radius;
+    state->dangerRects[2].top = state->dangerRects[3].top = bounds.bottom - radius;
+    for (int i = 0; i < 4; i++) {
+        transform->mapRect(state->dangerRects[i]);
+
+        // round danger rects out as though they are AA geometry (since they essentially are)
+        state->dangerRects[i].snapGeometryToPixelBoundaries(true);
+    }
+
+    // store RR area
+    bounds.inset(radius);
+    state->outlineInnerRect = bounds;
+    state->outlineRadius = radius;
+
+    // store as immutable so, for this frame, pointer uniquely identifies this bundle of shader info
+    roundRectClipState = state;
+}
+
+///////////////////////////////////////////////////////////////////////////////
 // Queries
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index e9ab1ff..435736c 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -20,6 +20,7 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
+#include <utils/LinearAllocator.h>
 #include <utils/RefBase.h>
 #include <ui/Region.h>
 
@@ -27,12 +28,40 @@
 
 #include "Layer.h"
 #include "Matrix.h"
+#include "Outline.h"
 #include "Rect.h"
+#include "utils/Macros.h"
 
 namespace android {
 namespace uirenderer {
 
 /**
+ * Temporary structure holding information for a single outline clip.
+ *
+ * These structures are treated as immutable once created, and only exist for a single frame, which
+ * is why they may only be allocated with a LinearAllocator.
+ */
+class RoundRectClipState {
+public:
+    /** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/
+    static void* operator new(size_t size, LinearAllocator& allocator) {
+        return allocator.alloc(size);
+    }
+
+    bool areaRequiresRoundRectClip(const Rect& rect) const {
+        return rect.intersects(dangerRects[0])
+                || rect.intersects(dangerRects[1])
+                || rect.intersects(dangerRects[2])
+                || rect.intersects(dangerRects[3]);
+    }
+
+    Matrix4 matrix;
+    Rect dangerRects[4];
+    Rect outlineInnerRect;
+    float outlineRadius;
+};
+
+/**
  * A snapshot holds information about the current state of the rendering
  * surface. A snapshot is usually created whenever the user calls save()
  * and discarded when the user calls restore(). Once a snapshot is created,
@@ -133,6 +162,11 @@
     const Matrix4& getOrthoMatrix() const { return mViewportData.mOrthoMatrix; }
 
     /**
+     * Sets (and replaces) the current clipping outline
+     */
+    void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
+
+    /**
      * Indicates whether this snapshot should be ignored. A snapshot
      * is typicalled ignored if its layer is invisible or empty.
      */
@@ -225,6 +259,14 @@
      */
     float alpha;
 
+    /**
+     * Current clipping round rect.
+     *
+     * Points to data not owned by the snapshot, and may only be replaced by subsequent RR clips,
+     * never modified.
+     */
+    const RoundRectClipState* roundRectClipState;
+
     void dump() const;
 
 private:
diff --git a/libs/hwui/StatefulBaseRenderer.cpp b/libs/hwui/StatefulBaseRenderer.cpp
index aa83e20..7d299f0 100644
--- a/libs/hwui/StatefulBaseRenderer.cpp
+++ b/libs/hwui/StatefulBaseRenderer.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "OpenGLRenderer"
+
 #include <SkCanvas.h>
 
 #include "StatefulBaseRenderer.h"
@@ -180,6 +182,10 @@
     return !mSnapshot->clipRect->isEmpty();
 }
 
+void StatefulBaseRenderer::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
+    mSnapshot->setClippingOutline(allocator, outline);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Quick Rejection
 ///////////////////////////////////////////////////////////////////////////////
@@ -195,7 +201,9 @@
  *         See Rect::snapGeometryToPixelBoundaries()
  */
 bool StatefulBaseRenderer::calculateQuickRejectForScissor(float left, float top,
-        float right, float bottom, bool* clipRequired, bool snapOut) const {
+        float right, float bottom,
+        bool* clipRequired, bool* roundRectClipRequired,
+        bool snapOut) const {
     if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
         return true;
     }
@@ -210,7 +218,15 @@
     if (!clipRect.intersects(r)) return true;
 
     // clip is required if geometry intersects clip rect
-    if (clipRequired) *clipRequired = !clipRect.contains(r);
+    if (clipRequired) {
+        *clipRequired = !clipRect.contains(r);
+    }
+
+    // round rect clip is required if RR clip exists, and geometry intersects its corners
+    if (roundRectClipRequired) {
+        *roundRectClipRequired = mSnapshot->roundRectClipState != NULL
+                && mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
+    }
     return false;
 }
 
diff --git a/libs/hwui/StatefulBaseRenderer.h b/libs/hwui/StatefulBaseRenderer.h
index 9fbf2ca..2e7f279 100644
--- a/libs/hwui/StatefulBaseRenderer.h
+++ b/libs/hwui/StatefulBaseRenderer.h
@@ -88,6 +88,14 @@
     virtual bool clipPath(const SkPath* path, SkRegion::Op op);
     virtual bool clipRegion(const SkRegion* region, SkRegion::Op op);
 
+    /**
+     * Does not support different clipping Ops (that is, every call to setClippingOutline is
+     * effectively using SkRegion::kReplaceOp)
+     *
+     * The clipping outline is independent from the regular clip.
+     */
+    void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
+
 protected:
     const Rect& getRenderTargetClipBounds() const { return mSnapshot->getRenderTargetClip(); }
 
@@ -106,7 +114,7 @@
 
     // Clip
     bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
-            bool* clipRequired, bool snapOut) const;
+            bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const;
 
     /**
      * Called just after a restore has occurred. The 'removed' snapshot popped from the stack,
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index fc5994c..d4a23b8 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -21,12 +21,12 @@
 namespace android {
 namespace uirenderer {
 
-class BaseAnimator;
+class BaseRenderNodeAnimator;
 class AnimationListener;
 
 class AnimationHook {
 public:
-    virtual void callOnFinished(BaseAnimator* animator, AnimationListener* listener) = 0;
+    virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) = 0;
 protected:
     ~AnimationHook() {}
 };
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index 1a7082b..997acde2 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -34,6 +34,10 @@
         return value >= gNonZeroEpsilon;
     }
 
+    inline static bool areEqual(float valueA, float valueB) {
+        return isZero(valueA - valueB);
+    }
+
     inline static int min(int a, int b) {
         return a < b ? a : b;
     }
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 384e120..d4e85c8 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -61,25 +61,25 @@
      */
     public static final int RECORDSTATE_RECORDING = 3;// matches SL_RECORDSTATE_RECORDING
 
-    // Error codes:
-    // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp
     /**
      * Denotes a successful operation.
      */
-    public static final int SUCCESS                 = 0;
+    public  static final int SUCCESS                               = AudioSystem.SUCCESS;
     /**
      * Denotes a generic operation failure.
      */
-    public static final int ERROR                   = -1;
+    public  static final int ERROR                                 = AudioSystem.ERROR;
     /**
      * Denotes a failure due to the use of an invalid value.
      */
-    public static final int ERROR_BAD_VALUE         = -2;
+    public  static final int ERROR_BAD_VALUE                       = AudioSystem.BAD_VALUE;
     /**
      * Denotes a failure due to the improper use of a method.
      */
-    public static final int ERROR_INVALID_OPERATION = -3;
+    public  static final int ERROR_INVALID_OPERATION               = AudioSystem.INVALID_OPERATION;
 
+    // Error codes:
+    // to keep in sync with frameworks/base/core/jni/android_media_AudioRecord.cpp
     private static final int AUDIORECORD_ERROR_SETUP_ZEROFRAMECOUNT      = -16;
     private static final int AUDIORECORD_ERROR_SETUP_INVALIDCHANNELMASK  = -17;
     private static final int AUDIORECORD_ERROR_SETUP_INVALIDFORMAT       = -18;
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 327c10c..5ddb198 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -199,6 +199,17 @@
         }
     }
 
+    /*
+     * Error codes used by public APIs (AudioTrack, AudioRecord, AudioManager ...)
+     * Must be kept in sync with frameworks/base/core/jni/android_media_AudioErrors.h
+     */
+    public static final int SUCCESS            = 0;
+    public static final int ERROR              = -1;
+    public static final int BAD_VALUE          = -2;
+    public static final int INVALID_OPERATION  = -3;
+    public static final int PERMISSION_DENIED  = -4;
+    public static final int NO_INIT            = -5;
+    public static final int DEAD_OBJECT        = -6;
 
     /*
      * AudioPolicyService methods
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 1a64cff..1baaaa4 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -125,25 +125,25 @@
      */
     public static final int STATE_NO_STATIC_DATA = 2;
 
-    // Error codes:
-    // to keep in sync with frameworks/base/core/jni/android_media_AudioTrack.cpp
     /**
      * Denotes a successful operation.
      */
-    public  static final int SUCCESS                               = 0;
+    public  static final int SUCCESS                               = AudioSystem.SUCCESS;
     /**
      * Denotes a generic operation failure.
      */
-    public  static final int ERROR                                 = -1;
+    public  static final int ERROR                                 = AudioSystem.ERROR;
     /**
      * Denotes a failure due to the use of an invalid value.
      */
-    public  static final int ERROR_BAD_VALUE                       = -2;
+    public  static final int ERROR_BAD_VALUE                       = AudioSystem.BAD_VALUE;
     /**
      * Denotes a failure due to the improper use of a method.
      */
-    public  static final int ERROR_INVALID_OPERATION               = -3;
+    public  static final int ERROR_INVALID_OPERATION               = AudioSystem.INVALID_OPERATION;
 
+    // Error codes:
+    // to keep in sync with frameworks/base/core/jni/android_media_AudioTrack.cpp
     private static final int ERROR_NATIVESETUP_AUDIOSYSTEM         = -16;
     private static final int ERROR_NATIVESETUP_INVALIDCHANNELMASK  = -17;
     private static final int ERROR_NATIVESETUP_INVALIDFORMAT       = -18;
diff --git a/media/java/android/media/TtmlRenderer.java b/media/java/android/media/TtmlRenderer.java
new file mode 100644
index 0000000..0309334
--- /dev/null
+++ b/media/java/android/media/TtmlRenderer.java
@@ -0,0 +1,751 @@
+/*
+ * 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.
+ */
+
+package android.media;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.media.SubtitleTrack.RenderingWidget.OnChangedListener;
+import android.text.Layout.Alignment;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup.LayoutParams;
+import android.view.accessibility.CaptioningManager;
+import android.view.accessibility.CaptioningManager.CaptionStyle;
+import android.view.accessibility.CaptioningManager.CaptioningChangeListener;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.widget.SubtitleView;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.TreeSet;
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+/** @hide */
+public class TtmlRenderer extends SubtitleController.Renderer {
+    private final Context mContext;
+
+    private static final String MEDIA_MIMETYPE_TEXT_TTML = "application/ttml+xml";
+
+    private TtmlRenderingWidget mRenderingWidget;
+
+    public TtmlRenderer(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public boolean supports(MediaFormat format) {
+        if (format.containsKey(MediaFormat.KEY_MIME)) {
+            return format.getString(MediaFormat.KEY_MIME).equals(MEDIA_MIMETYPE_TEXT_TTML);
+        }
+        return false;
+    }
+
+    @Override
+    public SubtitleTrack createTrack(MediaFormat format) {
+        if (mRenderingWidget == null) {
+            mRenderingWidget = new TtmlRenderingWidget(mContext);
+        }
+        return new TtmlTrack(mRenderingWidget, format);
+    }
+}
+
+/**
+ * A class which provides utillity methods for TTML parsing.
+ *
+ * @hide
+ */
+final class TtmlUtils {
+    public static final String TAG_TT = "tt";
+    public static final String TAG_HEAD = "head";
+    public static final String TAG_BODY = "body";
+    public static final String TAG_DIV = "div";
+    public static final String TAG_P = "p";
+    public static final String TAG_SPAN = "span";
+    public static final String TAG_BR = "br";
+    public static final String TAG_STYLE = "style";
+    public static final String TAG_STYLING = "styling";
+    public static final String TAG_LAYOUT = "layout";
+    public static final String TAG_REGION = "region";
+    public static final String TAG_METADATA = "metadata";
+    public static final String TAG_SMPTE_IMAGE = "smpte:image";
+    public static final String TAG_SMPTE_DATA = "smpte:data";
+    public static final String TAG_SMPTE_INFORMATION = "smpte:information";
+    public static final String PCDATA = "#pcdata";
+    public static final String ATTR_BEGIN = "begin";
+    public static final String ATTR_DURATION = "dur";
+    public static final String ATTR_END = "end";
+    public static final long INVALID_TIMESTAMP = Long.MAX_VALUE;
+
+    /**
+     * Time expression RE according to the spec:
+     * http://www.w3.org/TR/ttaf1-dfxp/#timing-value-timeExpression
+     */
+    private static final Pattern CLOCK_TIME = Pattern.compile(
+            "^([0-9][0-9]+):([0-9][0-9]):([0-9][0-9])"
+            + "(?:(\\.[0-9]+)|:([0-9][0-9])(?:\\.([0-9]+))?)?$");
+
+    private static final Pattern OFFSET_TIME = Pattern.compile(
+            "^([0-9]+(?:\\.[0-9]+)?)(h|m|s|ms|f|t)$");
+
+    private TtmlUtils() {
+    }
+
+    /**
+     * Parses the given time expression and returns a timestamp in millisecond.
+     * <p>
+     * For the format of the time expression, please refer <a href=
+     * "http://www.w3.org/TR/ttaf1-dfxp/#timing-value-timeExpression">timeExpression</a>
+     *
+     * @param time A string which includes time expression.
+     * @param frameRate the framerate of the stream.
+     * @param subframeRate the sub-framerate of the stream
+     * @param tickRate the tick rate of the stream.
+     * @return the parsed timestamp in micro-second.
+     * @throws NumberFormatException if the given string does not match to the
+     *             format.
+     */
+    public static long parseTimeExpression(String time, int frameRate, int subframeRate,
+            int tickRate) throws NumberFormatException {
+        Matcher matcher = CLOCK_TIME.matcher(time);
+        if (matcher.matches()) {
+            String hours = matcher.group(1);
+            double durationSeconds = Long.parseLong(hours) * 3600;
+            String minutes = matcher.group(2);
+            durationSeconds += Long.parseLong(minutes) * 60;
+            String seconds = matcher.group(3);
+            durationSeconds += Long.parseLong(seconds);
+            String fraction = matcher.group(4);
+            durationSeconds += (fraction != null) ? Double.parseDouble(fraction) : 0;
+            String frames = matcher.group(5);
+            durationSeconds += (frames != null) ? ((double)Long.parseLong(frames)) / frameRate : 0;
+            String subframes = matcher.group(6);
+            durationSeconds += (subframes != null) ? ((double)Long.parseLong(subframes))
+                    / subframeRate / frameRate
+                    : 0;
+            return (long)(durationSeconds * 1000);
+        }
+        matcher = OFFSET_TIME.matcher(time);
+        if (matcher.matches()) {
+            String timeValue = matcher.group(1);
+            double value = Double.parseDouble(timeValue);
+            String unit = matcher.group(2);
+            if (unit.equals("h")) {
+                value *= 3600L * 1000000L;
+            } else if (unit.equals("m")) {
+                value *= 60 * 1000000;
+            } else if (unit.equals("s")) {
+                value *= 1000000;
+            } else if (unit.equals("ms")) {
+                value *= 1000;
+            } else if (unit.equals("f")) {
+                value = value / frameRate * 1000000;
+            } else if (unit.equals("t")) {
+                value = value / tickRate * 1000000;
+            }
+            return (long)value;
+        }
+        throw new NumberFormatException("Malformed time expression : " + time);
+    }
+
+    /**
+     * Applies <a href
+     * src="http://www.w3.org/TR/ttaf1-dfxp/#content-attribute-space">the
+     * default space policy</a> to the given string.
+     *
+     * @param in A string to apply the policy.
+     */
+    public static String applyDefaultSpacePolicy(String in) {
+        return applySpacePolicy(in, true);
+    }
+
+    /**
+     * Applies the space policy to the given string. This applies <a href
+     * src="http://www.w3.org/TR/ttaf1-dfxp/#content-attribute-space">the
+     * default space policy</a> with linefeed-treatment as treat-as-space
+     * or preserve.
+     *
+     * @param in A string to apply the policy.
+     * @param treatLfAsSpace Whether convert line feeds to spaces or not.
+     */
+    public static String applySpacePolicy(String in, boolean treatLfAsSpace) {
+        // Removes CR followed by LF. ref:
+        // http://www.w3.org/TR/xml/#sec-line-ends
+        String crRemoved = in.replaceAll("\r\n", "\n");
+        // Apply suppress-at-line-break="auto" and
+        // white-space-treatment="ignore-if-surrounding-linefeed"
+        String spacesNeighboringLfRemoved = crRemoved.replaceAll(" *\n *", "\n");
+        // Apply linefeed-treatment="treat-as-space"
+        String lfToSpace = treatLfAsSpace ? spacesNeighboringLfRemoved.replaceAll("\n", " ")
+                : spacesNeighboringLfRemoved;
+        // Apply white-space-collapse="true"
+        String spacesCollapsed = lfToSpace.replaceAll("[ \t\\x0B\f\r]+", " ");
+        return spacesCollapsed;
+    }
+
+    /**
+     * Returns the timed text for the given time period.
+     *
+     * @param root The root node of the TTML document.
+     * @param startUs The start time of the time period in microsecond.
+     * @param endUs The end time of the time period in microsecond.
+     */
+    public static String extractText(TtmlNode root, long startUs, long endUs) {
+        StringBuilder text = new StringBuilder();
+        extractText(root, startUs, endUs, text, false);
+        return text.toString().replaceAll("\n$", "");
+    }
+
+    private static void extractText(TtmlNode node, long startUs, long endUs, StringBuilder out,
+            boolean inPTag) {
+        if (node.mName.equals(TtmlUtils.PCDATA) && inPTag) {
+            out.append(node.mText);
+        } else if (node.mName.equals(TtmlUtils.TAG_BR) && inPTag) {
+            out.append("\n");
+        } else if (node.mName.equals(TtmlUtils.TAG_METADATA)) {
+            // do nothing.
+        } else if (node.isActive(startUs, endUs)) {
+            boolean pTag = node.mName.equals(TtmlUtils.TAG_P);
+            int length = out.length();
+            for (int i = 0; i < node.mChildren.size(); ++i) {
+                extractText(node.mChildren.get(i), startUs, endUs, out, pTag || inPTag);
+            }
+            if (pTag && length != out.length()) {
+                out.append("\n");
+            }
+        }
+    }
+
+    /**
+     * Returns a TTML fragment string for the given time period.
+     *
+     * @param root The root node of the TTML document.
+     * @param startUs The start time of the time period in microsecond.
+     * @param endUs The end time of the time period in microsecond.
+     */
+    public static String extractTtmlFragment(TtmlNode root, long startUs, long endUs) {
+        StringBuilder fragment = new StringBuilder();
+        extractTtmlFragment(root, startUs, endUs, fragment);
+        return fragment.toString();
+    }
+
+    private static void extractTtmlFragment(TtmlNode node, long startUs, long endUs,
+            StringBuilder out) {
+        if (node.mName.equals(TtmlUtils.PCDATA)) {
+            out.append(node.mText);
+        } else if (node.mName.equals(TtmlUtils.TAG_BR)) {
+            out.append("<br/>");
+        } else if (node.isActive(startUs, endUs)) {
+            out.append("<");
+            out.append(node.mName);
+            out.append(node.mAttributes);
+            out.append(">");
+            for (int i = 0; i < node.mChildren.size(); ++i) {
+                extractTtmlFragment(node.mChildren.get(i), startUs, endUs, out);
+            }
+            out.append("</");
+            out.append(node.mName);
+            out.append(">");
+        }
+    }
+}
+
+/**
+ * A container class which represents a cue in TTML.
+ * @hide
+ */
+class TtmlCue extends SubtitleTrack.Cue {
+    public String mText;
+    public String mTtmlFragment;
+
+    public TtmlCue(long startTimeMs, long endTimeMs, String text, String ttmlFragment) {
+        this.mStartTimeMs = startTimeMs;
+        this.mEndTimeMs = endTimeMs;
+        this.mText = text;
+        this.mTtmlFragment = ttmlFragment;
+    }
+}
+
+/**
+ * A container class which represents a node in TTML.
+ *
+ * @hide
+ */
+class TtmlNode {
+    public final String mName;
+    public final String mAttributes;
+    public final TtmlNode mParent;
+    public final String mText;
+    public final List<TtmlNode> mChildren = new ArrayList<TtmlNode>();
+    public final long mRunId;
+    public final long mStartTimeMs;
+    public final long mEndTimeMs;
+
+    public TtmlNode(String name, String attributes, String text, long startTimeMs, long endTimeMs,
+            TtmlNode parent, long runId) {
+        this.mName = name;
+        this.mAttributes = attributes;
+        this.mText = text;
+        this.mStartTimeMs = startTimeMs;
+        this.mEndTimeMs = endTimeMs;
+        this.mParent = parent;
+        this.mRunId = runId;
+    }
+
+    /**
+     * Check if this node is active in the given time range.
+     *
+     * @param startTimeMs The start time of the range to check in microsecond.
+     * @param endTimeMs The end time of the range to check in microsecond.
+     * @return return true if the given range overlaps the time range of this
+     *         node.
+     */
+    public boolean isActive(long startTimeMs, long endTimeMs) {
+        return this.mEndTimeMs > startTimeMs && this.mStartTimeMs < endTimeMs;
+    }
+}
+
+/**
+ * A simple TTML parser (http://www.w3.org/TR/ttaf1-dfxp/) which supports DFXP
+ * presentation profile.
+ * <p>
+ * Supported features in this parser are:
+ * <ul>
+ * <li>content
+ * <li>core
+ * <li>presentation
+ * <li>profile
+ * <li>structure
+ * <li>time-offset
+ * <li>timing
+ * <li>tickRate
+ * <li>time-clock-with-frames
+ * <li>time-clock
+ * <li>time-offset-with-frames
+ * <li>time-offset-with-ticks
+ * </ul>
+ * </p>
+ *
+ * @hide
+ */
+class TtmlParser {
+    static final String TAG = "TtmlParser";
+
+    // TODO: read and apply the following attributes if specified.
+    private static final int DEFAULT_FRAMERATE = 30;
+    private static final int DEFAULT_SUBFRAMERATE = 1;
+    private static final int DEFAULT_TICKRATE = 1;
+
+    private XmlPullParser mParser;
+    private final TtmlNodeListener mListener;
+    private long mCurrentRunId;
+
+    public TtmlParser(TtmlNodeListener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Parse TTML data. Once this is called, all the previous data are
+     * reset and it starts parsing for the given text.
+     *
+     * @param ttmlText TTML text to parse.
+     * @throws XmlPullParserException
+     * @throws IOException
+     */
+    public void parse(String ttmlText, long runId) throws XmlPullParserException, IOException {
+        mParser = null;
+        mCurrentRunId = runId;
+        loadParser(ttmlText);
+        parseTtml();
+    }
+
+    private void loadParser(String ttmlFragment) throws XmlPullParserException {
+        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+        factory.setNamespaceAware(false);
+        mParser = factory.newPullParser();
+        StringReader in = new StringReader(ttmlFragment);
+        mParser.setInput(in);
+    }
+
+    private void extractAttribute(XmlPullParser parser, int i, StringBuilder out) {
+        out.append(" ");
+        out.append(parser.getAttributeName(i));
+        out.append("=\"");
+        out.append(parser.getAttributeValue(i));
+        out.append("\"");
+    }
+
+    private void parseTtml() throws XmlPullParserException, IOException {
+        LinkedList<TtmlNode> nodeStack = new LinkedList<TtmlNode>();
+        int depthInUnsupportedTag = 0;
+        boolean active = true;
+        while (!isEndOfDoc()) {
+            int eventType = mParser.getEventType();
+            TtmlNode parent = nodeStack.peekLast();
+            if (active) {
+                if (eventType == XmlPullParser.START_TAG) {
+                    if (!isSupportedTag(mParser.getName())) {
+                        Log.w(TAG, "Unsupported tag " + mParser.getName() + " is ignored.");
+                        depthInUnsupportedTag++;
+                        active = false;
+                    } else {
+                        TtmlNode node = parseNode(parent);
+                        nodeStack.addLast(node);
+                        if (parent != null) {
+                            parent.mChildren.add(node);
+                        }
+                    }
+                } else if (eventType == XmlPullParser.TEXT) {
+                    String text = TtmlUtils.applyDefaultSpacePolicy(mParser.getText());
+                    if (!TextUtils.isEmpty(text)) {
+                        parent.mChildren.add(new TtmlNode(
+                                TtmlUtils.PCDATA, "", text, 0, TtmlUtils.INVALID_TIMESTAMP,
+                                parent, mCurrentRunId));
+
+                    }
+                } else if (eventType == XmlPullParser.END_TAG) {
+                    if (mParser.getName().equals(TtmlUtils.TAG_P)) {
+                        mListener.onTtmlNodeParsed(nodeStack.getLast());
+                    } else if (mParser.getName().equals(TtmlUtils.TAG_TT)) {
+                        mListener.onRootNodeParsed(nodeStack.getLast());
+                    }
+                    nodeStack.removeLast();
+                }
+            } else {
+                if (eventType == XmlPullParser.START_TAG) {
+                    depthInUnsupportedTag++;
+                } else if (eventType == XmlPullParser.END_TAG) {
+                    depthInUnsupportedTag--;
+                    if (depthInUnsupportedTag == 0) {
+                        active = true;
+                    }
+                }
+            }
+            mParser.next();
+        }
+    }
+
+    private TtmlNode parseNode(TtmlNode parent) throws XmlPullParserException, IOException {
+        int eventType = mParser.getEventType();
+        if (!(eventType == XmlPullParser.START_TAG)) {
+            return null;
+        }
+        StringBuilder attrStr = new StringBuilder();
+        long start = 0;
+        long end = TtmlUtils.INVALID_TIMESTAMP;
+        long dur = 0;
+        for (int i = 0; i < mParser.getAttributeCount(); ++i) {
+            String attr = mParser.getAttributeName(i);
+            String value = mParser.getAttributeValue(i);
+            // TODO: check if it's safe to ignore the namespace of attributes as follows.
+            attr = attr.replaceFirst("^.*:", "");
+            if (attr.equals(TtmlUtils.ATTR_BEGIN)) {
+                start = TtmlUtils.parseTimeExpression(value, DEFAULT_FRAMERATE,
+                        DEFAULT_SUBFRAMERATE, DEFAULT_TICKRATE);
+            } else if (attr.equals(TtmlUtils.ATTR_END)) {
+                end = TtmlUtils.parseTimeExpression(value, DEFAULT_FRAMERATE, DEFAULT_SUBFRAMERATE,
+                        DEFAULT_TICKRATE);
+            } else if (attr.equals(TtmlUtils.ATTR_DURATION)) {
+                dur = TtmlUtils.parseTimeExpression(value, DEFAULT_FRAMERATE, DEFAULT_SUBFRAMERATE,
+                        DEFAULT_TICKRATE);
+            } else {
+                extractAttribute(mParser, i, attrStr);
+            }
+        }
+        if (parent != null) {
+            start += parent.mStartTimeMs;
+            if (end != TtmlUtils.INVALID_TIMESTAMP) {
+                end += parent.mStartTimeMs;
+            }
+        }
+        if (dur > 0) {
+            if (end != TtmlUtils.INVALID_TIMESTAMP) {
+                Log.e(TAG, "'dur' and 'end' attributes are defined at the same time." +
+                        "'end' value is ignored.");
+            }
+            end = start + dur;
+        }
+        if (parent != null) {
+            // If the end time remains unspecified, then the end point is
+            // interpreted as the end point of the external time interval.
+            if (end == TtmlUtils.INVALID_TIMESTAMP &&
+                    parent.mEndTimeMs != TtmlUtils.INVALID_TIMESTAMP &&
+                    end > parent.mEndTimeMs) {
+                end = parent.mEndTimeMs;
+            }
+        }
+        TtmlNode node = new TtmlNode(mParser.getName(), attrStr.toString(), null, start, end,
+                parent, mCurrentRunId);
+        return node;
+    }
+
+    private boolean isEndOfDoc() throws XmlPullParserException {
+        return (mParser.getEventType() == XmlPullParser.END_DOCUMENT);
+    }
+
+    private static boolean isSupportedTag(String tag) {
+        if (tag.equals(TtmlUtils.TAG_TT) || tag.equals(TtmlUtils.TAG_HEAD) ||
+                tag.equals(TtmlUtils.TAG_BODY) || tag.equals(TtmlUtils.TAG_DIV) ||
+                tag.equals(TtmlUtils.TAG_P) || tag.equals(TtmlUtils.TAG_SPAN) ||
+                tag.equals(TtmlUtils.TAG_BR) || tag.equals(TtmlUtils.TAG_STYLE) ||
+                tag.equals(TtmlUtils.TAG_STYLING) || tag.equals(TtmlUtils.TAG_LAYOUT) ||
+                tag.equals(TtmlUtils.TAG_REGION) || tag.equals(TtmlUtils.TAG_METADATA) ||
+                tag.equals(TtmlUtils.TAG_SMPTE_IMAGE) || tag.equals(TtmlUtils.TAG_SMPTE_DATA) ||
+                tag.equals(TtmlUtils.TAG_SMPTE_INFORMATION)) {
+            return true;
+        }
+        return false;
+    }
+}
+
+/** @hide */
+interface TtmlNodeListener {
+    void onTtmlNodeParsed(TtmlNode node);
+    void onRootNodeParsed(TtmlNode node);
+}
+
+/** @hide */
+class TtmlTrack extends SubtitleTrack implements TtmlNodeListener {
+    private static final String TAG = "TtmlTrack";
+
+    private final TtmlParser mParser = new TtmlParser(this);
+    private final TtmlRenderingWidget mRenderingWidget;
+    private String mParsingData;
+    private Long mCurrentRunID;
+
+    private final LinkedList<TtmlNode> mTtmlNodes;
+    private final TreeSet<Long> mTimeEvents;
+    private TtmlNode mRootNode;
+
+    TtmlTrack(TtmlRenderingWidget renderingWidget, MediaFormat format) {
+        super(format);
+
+        mTtmlNodes = new LinkedList<TtmlNode>();
+        mTimeEvents = new TreeSet<Long>();
+        mRenderingWidget = renderingWidget;
+        mParsingData = "";
+    }
+
+    @Override
+    public TtmlRenderingWidget getRenderingWidget() {
+        return mRenderingWidget;
+    }
+
+    @Override
+    public void onData(String data, boolean eos, long runID) {
+        // implement intermixing restriction for TTML.
+        synchronized(mParser) {
+            if (mCurrentRunID != null && runID != mCurrentRunID) {
+                throw new IllegalStateException(
+                        "Run #" + mCurrentRunID +
+                        " in progress.  Cannot process run #" + runID);
+            }
+            mCurrentRunID = runID;
+            mParsingData += data;
+            if (eos) {
+                try {
+                    mParser.parse(mParsingData, mCurrentRunID);
+                } catch (XmlPullParserException e) {
+                    e.printStackTrace();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+                finishedRun(runID);
+                mParsingData = "";
+                mCurrentRunID = null;
+            }
+        }
+    }
+
+    @Override
+    public void onTtmlNodeParsed(TtmlNode node) {
+        mTtmlNodes.addLast(node);
+        addTimeEvents(node);
+    }
+
+    @Override
+    public void onRootNodeParsed(TtmlNode node) {
+        mRootNode = node;
+        TtmlCue cue = null;
+        while ((cue = getNextResult()) != null) {
+            addCue(cue);
+        }
+        mRootNode = null;
+        mTtmlNodes.clear();
+        mTimeEvents.clear();
+    }
+
+    @Override
+    public void updateView(Vector<SubtitleTrack.Cue> activeCues) {
+        if (!mVisible) {
+            // don't keep the state if we are not visible
+            return;
+        }
+
+        if (DEBUG && mTimeProvider != null) {
+            try {
+                Log.d(TAG, "at " +
+                        (mTimeProvider.getCurrentTimeUs(false, true) / 1000) +
+                        " ms the active cues are:");
+            } catch (IllegalStateException e) {
+                Log.d(TAG, "at (illegal state) the active cues are:");
+            }
+        }
+
+        mRenderingWidget.setActiveCues(activeCues);
+    }
+
+    /**
+     * Returns a {@link TtmlCue} in the presentation time order.
+     * {@code null} is returned if there is no more timed text to show.
+     */
+    public TtmlCue getNextResult() {
+        while (mTimeEvents.size() >= 2) {
+            long start = mTimeEvents.pollFirst();
+            long end = mTimeEvents.first();
+            List<TtmlNode> activeCues = getActiveNodes(start, end);
+            if (!activeCues.isEmpty()) {
+                return new TtmlCue(start, end,
+                        TtmlUtils.applySpacePolicy(TtmlUtils.extractText(
+                                mRootNode, start, end), false),
+                        TtmlUtils.extractTtmlFragment(mRootNode, start, end));
+            }
+        }
+        return null;
+    }
+
+    private void addTimeEvents(TtmlNode node) {
+        mTimeEvents.add(node.mStartTimeMs);
+        mTimeEvents.add(node.mEndTimeMs);
+        for (int i = 0; i < node.mChildren.size(); ++i) {
+            addTimeEvents(node.mChildren.get(i));
+        }
+    }
+
+    private List<TtmlNode> getActiveNodes(long startTimeUs, long endTimeUs) {
+        List<TtmlNode> activeNodes = new ArrayList<TtmlNode>();
+        for (int i = 0; i < mTtmlNodes.size(); ++i) {
+            TtmlNode node = mTtmlNodes.get(i);
+            if (node.isActive(startTimeUs, endTimeUs)) {
+                activeNodes.add(node);
+            }
+        }
+        return activeNodes;
+    }
+}
+
+/**
+ * Widget capable of rendering TTML captions.
+ *
+ * @hide
+ */
+class TtmlRenderingWidget extends LinearLayout implements SubtitleTrack.RenderingWidget {
+
+    /** Callback for rendering changes. */
+    private OnChangedListener mListener;
+    private final TextView mTextView;
+
+    public TtmlRenderingWidget(Context context) {
+        this(context, null);
+    }
+
+    public TtmlRenderingWidget(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public TtmlRenderingWidget(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public TtmlRenderingWidget(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        // Cannot render text over video when layer type is hardware.
+        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
+
+        CaptioningManager captionManager = (CaptioningManager) context.getSystemService(
+                Context.CAPTIONING_SERVICE);
+        mTextView = new TextView(context);
+        mTextView.setTextColor(captionManager.getUserStyle().foregroundColor);
+        addView(mTextView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+        mTextView.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
+    }
+
+    @Override
+    public void setOnChangedListener(OnChangedListener listener) {
+        mListener = listener;
+    }
+
+    @Override
+    public void setSize(int width, int height) {
+        final int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+        final int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+
+        measure(widthSpec, heightSpec);
+        layout(0, 0, width, height);
+    }
+
+    @Override
+    public void setVisible(boolean visible) {
+        if (visible) {
+            setVisibility(View.VISIBLE);
+        } else {
+            setVisibility(View.GONE);
+        }
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+    }
+
+    public void setActiveCues(Vector<SubtitleTrack.Cue> activeCues) {
+        final int count = activeCues.size();
+        String subtitleText = "";
+        for (int i = 0; i < count; i++) {
+            TtmlCue cue = (TtmlCue) activeCues.get(i);
+            subtitleText += cue.mText + "\n";
+        }
+        mTextView.setText(subtitleText);
+
+        if (mListener != null) {
+            mListener.onChanged(this);
+        }
+    }
+}
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 3ff07d9..096550f 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -40,6 +40,7 @@
     boolean setRoute(in RouteInfo route);
     void setRouteOptions(in List<RouteOptions> options);
     void connectToRoute(in RouteInfo route, in RouteOptions options);
+    void disconnectFromRoute(in RouteInfo route);
     void sendRouteCommand(in RouteCommand event, in ResultReceiver cb);
 
     // These commands are for the TransportPerformer
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index f04cbcc..1552513 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -31,6 +31,7 @@
     void onMediaButton(in Intent mediaButtonIntent);
     void onRequestRouteChange(in RouteInfo route);
     void onRouteConnected(in RouteInfo route, in RouteOptions options);
+    void onRouteDisconnected(in RouteInfo route, int reason);
     void onRouteStateChange(int state);
     void onRouteEvent(in RouteEvent event);
 
diff --git a/media/java/android/media/session/Session.java b/media/java/android/media/session/Session.java
index 194679e7..2ffced6 100644
--- a/media/java/android/media/session/Session.java
+++ b/media/java/android/media/session/Session.java
@@ -86,10 +86,39 @@
      */
     public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16;
 
+    /**
+     * Indicates the session was disconnected because the user that the session
+     * belonged to is stopping.
+     */
+    public static final int DISCONNECT_REASON_USER_STOPPING = 1;
+
+    /**
+     * Indicates the session was disconnected because the provider disconnected
+     * the route.
+     */
+    public static final int DISCONNECT_REASON_PROVIDER_DISCONNECTED = 2;
+
+    /**
+     * Indicates the session was disconnected because the route has changed.
+     */
+    public static final int DISCONNECT_REASON_ROUTE_CHANGED = 3;
+
+    /**
+     * Indicates the session was disconnected because the session owner
+     * requested it disconnect.
+     */
+    public static final int DISCONNECT_REASON_SESSION_DISCONNECTED = 4;
+
+    /**
+     * Indicates the session was disconnected because it was destroyed.
+     */
+    public static final int DISCONNECT_REASON_SESSION_DESTROYED = 5;
+
     private static final int MSG_MEDIA_BUTTON = 1;
     private static final int MSG_COMMAND = 2;
     private static final int MSG_ROUTE_CHANGE = 3;
     private static final int MSG_ROUTE_CONNECTED = 4;
+    private static final int MSG_ROUTE_DISCONNECTED = 5;
 
     private static final String KEY_COMMAND = "command";
     private static final String KEY_EXTRAS = "extras";
@@ -302,11 +331,15 @@
     /**
      * Disconnect from the current route. After calling you will be switched
      * back to the default route.
-     *
-     * @param route The route to disconnect from.
      */
-    public void disconnect(RouteInfo route) {
-        // TODO
+    public void disconnect() {
+        if (mRoute != null) {
+            try {
+                mBinder.disconnectFromRoute(mRoute.getRouteInfo());
+            } catch (RemoteException e) {
+                Log.wtf(TAG, "Error disconnecting from route");
+            }
+        }
     }
 
     /**
@@ -406,6 +439,16 @@
         }
     }
 
+    private void postRouteDisconnected(RouteInfo route, int reason) {
+        synchronized (mLock) {
+            if (mRoute != null && TextUtils.equals(mRoute.getRouteInfo().getId(), route.getId())) {
+                for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+                    mCallbacks.get(i).post(MSG_ROUTE_DISCONNECTED, mRoute, reason);
+                }
+            }
+        }
+    }
+
     /**
      * Receives commands or updates from controllers and routes. An app can
      * specify what commands and buttons it supports by setting them on the
@@ -467,6 +510,11 @@
          * <p>
          * Valid reasons are:
          * <ul>
+         * <li>{@link #DISCONNECT_REASON_USER_STOPPING}</li>
+         * <li>{@link #DISCONNECT_REASON_PROVIDER_DISCONNECTED}</li>
+         * <li>{@link #DISCONNECT_REASON_ROUTE_CHANGED}</li>
+         * <li>{@link #DISCONNECT_REASON_SESSION_DISCONNECTED}</li>
+         * <li>{@link #DISCONNECT_REASON_SESSION_DESTROYED}</li>
          * </ul>
          *
          * @param route The route that disconnected
@@ -520,6 +568,14 @@
         }
 
         @Override
+        public void onRouteDisconnected(RouteInfo route, int reason) {
+            Session session = mMediaSession.get();
+            if (session != null) {
+                session.postRouteDisconnected(route, reason);
+            }
+        }
+
+        @Override
         public void onPlay() throws RemoteException {
             Session session = mMediaSession.get();
             if (session != null) {
@@ -668,6 +724,9 @@
                     case MSG_ROUTE_CONNECTED:
                         mCallback.onRouteConnected((Route) msg.obj);
                         break;
+                    case MSG_ROUTE_DISCONNECTED:
+                        mCallback.onRouteDisconnected((Route) msg.obj, msg.arg1);
+                        break;
                 }
             }
         }
@@ -675,6 +734,10 @@
         public void post(int what, Object obj) {
             obtainMessage(what, obj).sendToTarget();
         }
+
+        public void post(int what, Object obj, int arg1) {
+            obtainMessage(what, arg1, 0, obj).sendToTarget();
+        }
     }
 
     private static final class Command {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 89886ef..8a7e642 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -23,10 +23,10 @@
 import android.hardware.IProCameraCallbacks;
 import android.hardware.IProCameraUser;
 import android.hardware.camera2.CameraMetadata;
-import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.utils.BinderHolder;
 import android.hardware.camera2.utils.CameraBinderDecorator;
 import android.os.Binder;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 74ce997..7b2e7dd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -21,10 +21,10 @@
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.utils.BinderHolder;
 import android.media.Image;
 import android.media.ImageReader;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
index 5ab586f..a77b647 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraMetadataTest.java
@@ -18,6 +18,7 @@
 
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Range;
+import android.util.Rational;
 import android.util.SizeF;
 import android.graphics.ImageFormat;
 import android.graphics.Point;
@@ -26,15 +27,14 @@
 import android.graphics.SurfaceTexture;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureResult;
-import android.hardware.camera2.ColorSpaceTransform;
-import android.hardware.camera2.Face;
-import android.hardware.camera2.MeteringRectangle;
-import android.hardware.camera2.Rational;
-import android.hardware.camera2.RggbChannelVector;
-import android.hardware.camera2.Size;
+import android.util.Size;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.marshal.impl.MarshalQueryableEnum;
+import android.hardware.camera2.params.ColorSpaceTransform;
+import android.hardware.camera2.params.Face;
+import android.hardware.camera2.params.MeteringRectangle;
 import android.hardware.camera2.params.ReprocessFormatsMap;
+import android.hardware.camera2.params.RggbChannelVector;
 import android.hardware.camera2.params.StreamConfiguration;
 import android.hardware.camera2.params.StreamConfigurationDuration;
 import android.hardware.camera2.params.StreamConfigurationMap;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
index 9621f92..18c0d3e 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java
@@ -17,7 +17,7 @@
 package com.android.mediaframeworktest.unit;
 
 import android.test.suitebuilder.annotation.SmallTest;
-import android.hardware.camera2.Rational;
+import android.util.Rational;
 
 /**
  * <pre>
diff --git a/packages/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml b/packages/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml
index b48e011..b363ab4 100644
--- a/packages/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml
+++ b/packages/Keyguard/test/SampleTrustAgent/res/xml/sample_trust_agent.xml
@@ -14,5 +14,5 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<trust_agent xmlns:android="http://schemas.android.com/apk/res/android"
+<trust-agent xmlns:android="http://schemas.android.com/apk/res/android"
         android:settingsActivity=".SampleTrustAgentSettings" />
diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
index 25406d6..a51ea75 100644
--- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
+++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java
@@ -31,7 +31,7 @@
 
     LocalBroadcastManager mLocalBroadcastManager;
 
-    private static final String ACTION_ENABLE_TRUST = "action.sample_trust_agent.enable_trust";
+    private static final String ACTION_GRANT_TRUST = "action.sample_trust_agent.grant_trust";
     private static final String ACTION_REVOKE_TRUST = "action.sample_trust_agent.revoke_trust";
 
     private static final String EXTRA_MESSAGE = "extra.message";
@@ -45,14 +45,14 @@
     public void onCreate() {
         super.onCreate();
         IntentFilter filter = new IntentFilter();
-        filter.addAction(ACTION_ENABLE_TRUST);
+        filter.addAction(ACTION_GRANT_TRUST);
         filter.addAction(ACTION_REVOKE_TRUST);
         mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
         mLocalBroadcastManager.registerReceiver(mReceiver, filter);
     }
 
     @Override
-    protected void onUnlockAttempt(boolean successful) {
+    public void onUnlockAttempt(boolean successful) {
         if (getReportUnlockAttempts(this)) {
             Toast.makeText(this, "onUnlockAttempt(successful=" + successful + ")",
                     Toast.LENGTH_SHORT).show();
@@ -69,8 +69,8 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            if (ACTION_ENABLE_TRUST.equals(action)) {
-                enableTrust(intent.getStringExtra(EXTRA_MESSAGE),
+            if (ACTION_GRANT_TRUST.equals(action)) {
+                grantTrust(intent.getStringExtra(EXTRA_MESSAGE),
                         intent.getLongExtra(EXTRA_DURATION, 0),
                         false /* initiatedByUser */);
             } else if (ACTION_REVOKE_TRUST.equals(action)) {
@@ -79,9 +79,9 @@
         }
     };
 
-    public static void sendEnableTrust(Context context,
+    public static void sendGrantTrust(Context context,
             String message, long durationMs, Bundle extra) {
-        Intent intent = new Intent(ACTION_ENABLE_TRUST);
+        Intent intent = new Intent(ACTION_GRANT_TRUST);
         intent.putExtra(EXTRA_MESSAGE, message);
         intent.putExtra(EXTRA_DURATION, durationMs);
         intent.putExtra(EXTRA_EXTRA, extra);
diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
index 0a6f675..8e293fb 100644
--- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
+++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java
@@ -19,7 +19,6 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.os.Bundle;
-import android.preference.CheckBoxPreference;
 import android.view.View;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
@@ -53,7 +52,7 @@
     public void onClick(View v) {
         int id = v.getId();
         if (id == R.id.enable_trust) {
-            SampleTrustAgent.sendEnableTrust(this, "SampleTrustAgent", TRUST_DURATION_MS,
+            SampleTrustAgent.sendGrantTrust(this, "SampleTrustAgent", TRUST_DURATION_MS,
                     null /* extra */);
         } else if (id == R.id.revoke_trust) {
             SampleTrustAgent.sendRevokeTrust(this);
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_location_off.png
deleted file mode 100644
index 189f27b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_location_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_location_on.png
deleted file mode 100644
index b03d30c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_location_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_location_off.png
deleted file mode 100644
index b692107..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_location_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_location_on.png
deleted file mode 100644
index 867c57d..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_location_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_off.png
deleted file mode 100644
index 7ce8f83..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_on.png
deleted file mode 100644
index 6300bdc..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_location_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_off.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_off.png
deleted file mode 100644
index c14c1bb..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_on.png
deleted file mode 100644
index d6d4c70..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_location_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_location_24_01.xml b/packages/SystemUI/res/drawable/ic_location_24_01.xml
new file mode 100644
index 0000000..ff37d9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_01.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M12.0,2.0C8.13,2.0 5.0,5.13 5.0,9.0c0.0,5.25 7.0,13.0 7.0,13.0s7.0,-7.75 7.0,-13.0C19.0,5.13 15.87,2.0 12.0,2.0zM12.0,11.5c-1.38,0.0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5c1.38,0.0 2.5,1.12 2.5,2.5S13.38,11.5 12.0,11.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_02.xml b/packages/SystemUI/res/drawable/ic_location_24_02.xml
new file mode 100644
index 0000000..bb4465f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_02.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M12.0,4.0c-3.48,0.0 -6.3,2.82 -6.3,6.3C5.7,15.02 12.0,22.0 12.0,22.0s6.3,-6.98 6.3,-11.7C18.3,6.82 15.48,4.0 12.0,4.0zM12.0,12.55c-1.24,0.0 -2.25,-1.01 -2.25,-2.25S10.76,8.05 12.0,8.05c1.24,0.0 2.25,1.01 2.25,2.25S13.24,12.55 12.0,12.55z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_03.xml b/packages/SystemUI/res/drawable/ic_location_24_03.xml
new file mode 100644
index 0000000..956a8c3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_03.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M12.0,7.0c-2.9,0.0 -5.25,2.35 -5.25,5.25C6.75,16.19 12.0,22.0 12.0,22.0s5.25,-5.81 5.25,-9.75C17.25,9.35 14.9,7.0 12.0,7.0zM12.0,14.12c-1.04,0.0 -1.88,-0.84 -1.88,-1.88s0.84,-1.88 1.88,-1.88c1.04,0.0 1.87,0.84 1.87,1.88S13.04,14.12 12.0,14.12z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_04.xml b/packages/SystemUI/res/drawable/ic_location_24_04.xml
new file mode 100644
index 0000000..0c0fb3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_04.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M12.0,10.0c-2.32,0.0 -4.2,1.88 -4.2,4.2C7.8,17.35 12.0,22.0 12.0,22.0s4.2,-4.65 4.2,-7.8C16.2,11.88 14.32,10.0 12.0,10.0zM12.0,15.7c-0.83,0.0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5c0.83,0.0 1.5,0.67 1.5,1.5S12.83,15.7 12.0,15.7z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_05.xml b/packages/SystemUI/res/drawable/ic_location_24_05.xml
new file mode 100644
index 0000000..1a21e2f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_05.xml
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M12.0,13.0c-1.74,0.0 -3.15,1.41 -3.15,3.15C8.85,18.51 12.0,22.0 12.0,22.0s3.15,-3.49 3.15,-5.85C15.15,14.41 13.74,13.0 12.0,13.0zM12.0,17.27c-0.62,0.0 -1.13,-0.5 -1.13,-1.12c0.0,-0.62 0.5,-1.12 1.13,-1.12c0.62,0.0 1.12,0.5 1.12,1.12C13.12,16.77 12.62,17.27 12.0,17.27z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_06.xml b/packages/SystemUI/res/drawable/ic_location_24_06.xml
new file mode 100644
index 0000000..25c9ae5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_06.xml
@@ -0,0 +1,33 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:fill="#FFFFFFFF"
+        android:pathData="M12.0,16.0c-1.16,0.0 -2.1,0.94 -2.1,2.1C9.9,19.67 12.0,22.0 12.0,22.0s2.1,-2.33 2.1,-3.9C14.1,16.94 13.16,16.0 12.0,16.0zM12.0,18.85c-0.41,0.0 -0.75,-0.34 -0.75,-0.75s0.34,-0.75 0.75,-0.75c0.41,0.0 0.75,0.34 0.75,0.75S12.41,18.85 12.0,18.85z"/>
+    <path
+        android:pathData="M11.99,15c-1.35,0,-2.45,1.1,-2.45,2.45      c0,1.84,2.45,4.55,2.45,4.55s2.45,-2.71,2.45,-4.55C14.44,16.1,13.34,15,11.99,15z M11.99,18.33c-0.48,0,-0.88,-0.39,-0.88,-0.88      s0.39,-0.88,0.88,-0.88c0.48,0,0.87,0.39,0.87,0.88S12.47,18.33,11.99,18.33z"
+        android:strokeWidth=".35"
+        android:fill="#00000000"
+        android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_07.xml b/packages/SystemUI/res/drawable/ic_location_24_07.xml
new file mode 100644
index 0000000..a69c3a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_07.xml
@@ -0,0 +1,30 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:pathData="M12,9c-2.51,0,-4.55,2.04,-4.55,4.55       C7.45,16.96,12,22,12,22s4.55,-5.04,4.55,-8.45C16.55,11.04,14.51,9,12,9z M12,15.18c-0.9,0,-1.63,-0.73,-1.63,-1.62       s0.73,-1.62,1.63,-1.62c0.9,0,1.62,0.73,1.62,1.62S12.9,15.18,12,15.18z"
+        android:strokeWidth="0.65"
+        android:fill="#00000000"
+        android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_08.xml b/packages/SystemUI/res/drawable/ic_location_24_08.xml
new file mode 100644
index 0000000..c89c047
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_08.xml
@@ -0,0 +1,30 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:pathData="M12,6c-3.09,0,-5.6,2.51,-5.6,5.6       C6.4,15.8,12,22,12,22s5.6,-6.2,5.6,-10.4C17.6,8.51,15.09,6,12,6z M12,13.6c-1.1,0,-2,-0.9,-2,-2s0.9,-2,2,-2c1.1,0,2,0.9,2,2       S13.1,13.6,12,13.6z"
+        android:strokeWidth="0.8"
+        android:fill="#00000000"
+        android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_09.xml b/packages/SystemUI/res/drawable/ic_location_24_09.xml
new file mode 100644
index 0000000..96bb6ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_09.xml
@@ -0,0 +1,30 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:pathData="M12,4c-3.48,0,-6.3,2.82,-6.3,6.3       C5.7,15.02,12,22,12,22s6.3,-6.98,6.3,-11.7C18.3,6.82,15.48,4,12,4z M12,12.55c-1.24,0,-2.25,-1.01,-2.25,-2.25S10.76,8.05,12,8.05       c1.24,0,2.25,1.01,2.25,2.25S13.24,12.55,12,12.55z"
+        android:strokeWidth="0.9"
+        android:fill="#00000000"
+        android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_10.xml b/packages/SystemUI/res/drawable/ic_location_24_10.xml
new file mode 100644
index 0000000..aced4bd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_10.xml
@@ -0,0 +1,30 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:pathData="M12,3C8.33,3,5.35,5.98,5.35,9.65       C5.35,14.64,12,22,12,22s6.65,-7.36,6.65,-12.35C18.65,5.98,15.67,3,12,3z M12,12.02c-1.31,0,-2.38,-1.06,-2.38,-2.38       S10.69,7.28,12,7.28c1.31,0,2.37,1.06,2.37,2.37S13.31,12.02,12,12.02z"
+        android:strokeWidth="0.95"
+        android:fill="#00000000"
+        android:stroke="#CCCCCC"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_24_11.xml b/packages/SystemUI/res/drawable/ic_location_24_11.xml
new file mode 100644
index 0000000..578308e3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_24_11.xml
@@ -0,0 +1,30 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size
+        android:width="64dp"
+        android:height="64dp"/>
+
+    <viewport
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"/>
+
+    <path
+        android:pathData="M12,2C8.13,2,5,5.13,5,9c0,5.25,7,13,7,13s7,-7.75,7,-13       C19,5.13,15.87,2,12,2z M12,11.5c-1.38,0,-2.5,-1.12,-2.5,-2.5s1.12,-2.5,2.5,-2.5c1.38,0,2.5,1.12,2.5,2.5S13.38,11.5,12,11.5z"
+        android:fill="#00000000"
+        android:stroke="#CCCCCC"
+        android:strokeWidth="1.0"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location_off_anim.xml b/packages/SystemUI/res/drawable/ic_location_off_anim.xml
new file mode 100644
index 0000000..864eda1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_off_anim.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<animation-list
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:oneshot="true">
+    <item android:drawable="@drawable/ic_location_24_01" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_02" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_03" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_04" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_05" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_06" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_07" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_08" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_09" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_10" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_11" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_location_on_anim.xml b/packages/SystemUI/res/drawable/ic_location_on_anim.xml
new file mode 100644
index 0000000..65a8afe
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location_on_anim.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<animation-list
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:oneshot="true">
+    <item android:drawable="@drawable/ic_location_24_11" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_10" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_09" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_08" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_07" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_06" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_05" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_04" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_03" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_02" android:duration="16" />
+    <item android:drawable="@drawable/ic_location_24_01" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
new file mode 100644
index 0000000..ff8800c
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
@@ -0,0 +1,65 @@
+<!--
+  ~ 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
+  -->
+
+<!-- Extends FrameLayout -->
+<com.android.systemui.statusbar.SpeedBumpView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:focusable="true"
+    android:clickable="true"
+    android:visibility="gone"
+    >
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/speed_bump_height_collapsed"
+            android:layout_gravity="top"
+            android:orientation="horizontal">
+        <View
+            android:id="@+id/speedbump_line_left"
+            android:layout_width="0dp"
+            android:layout_height="1dp"
+            android:layout_weight="1"
+            android:background="#6fdddddd"
+            android:layout_gravity="center_vertical"/>
+        <com.android.systemui.statusbar.SpeedBumpDotsLayout
+                android:id="@+id/speed_bump_dots_layout"
+                android:layout_width="34dp"
+                android:layout_marginStart="8dp"
+                android:layout_marginEnd="8dp"
+                android:layout_height="match_parent"
+                android:layout_weight="0"/>
+        <View
+            android:id="@+id/speedbump_line_right"
+            android:layout_width="0dp"
+            android:layout_height="1dp"
+            android:layout_weight="1"
+            android:background="#6fdddddd"
+            android:layout_gravity="center_vertical"/>
+    </LinearLayout>
+    <TextView
+            android:id="@+id/speed_bump_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top|center_horizontal"
+            android:fontFamily="sans-serif-condensed"
+            android:textSize="15sp"
+            android:singleLine="true"
+            android:textColor="#eeeeee"
+            android:visibility="invisible"
+            android:text="@string/speed_bump_explanation"
+            android:paddingTop="4dp" />
+</com.android.systemui.statusbar.SpeedBumpView>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 7de1bd0..cba13004 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -22,6 +22,7 @@
     <drawable name="system_bar_background">@color/system_bar_background_opaque</drawable>
     <color name="system_bar_background_opaque">#ff000000</color>
     <color name="system_bar_background_semi_transparent">#66000000</color> <!-- 40% black -->
+    <color name="system_bar_background_transparent">#00000000</color>
     <color name="notification_panel_solid_background">#ff000000</color>
     <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable>
     <color name="status_bar_recents_app_label_color">#ffffffff</color>
@@ -57,6 +58,18 @@
     <!-- Tint color for the content on the notification overflow card. -->
     <color name="keyguard_overflow_content_color">#ff666666</color>
 
+    <!-- The color of the red speed bump dot -->
+    <color name="speed_bump_dot_red">#ffd50000</color>
+
+    <!-- The color of the blue speed bump dot -->
+    <color name="speed_bump_dot_blue">#ff2962ff</color>
+
+    <!-- The color of the yellow speed bump dot -->
+    <color name="speed_bump_dot_yellow">#ffffd600</color>
+
+    <!-- The color of the green speed bump dot -->
+    <color name="speed_bump_dot_green">#ff00c853</color>
+
     <!-- The default recents task bar background color. -->
     <color name="recents_task_bar_default_background_color">#e6444444</color>
     <!-- The default recents task bar text color. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 79612e0..d403bf3 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -260,6 +260,15 @@
     <!-- The padding between the individual notification cards. -->
     <dimen name="notification_padding">4dp</dimen>
 
+    <!-- The height of the collapsed speed bump view. -->
+    <dimen name="speed_bump_height_collapsed">24dp</dimen>
+
+    <!-- The padding inset the explanation text needs compared to the collapsed height -->
+    <dimen name="speed_bump_text_padding_inset">10dp</dimen>
+
+    <!-- The height of the speed bump dots. -->
+    <dimen name="speed_bump_dots_height">5dp</dimen>
+
     <!-- The total height of the stack in its collapsed size (i.e. when quick settings is open) -->
     <dimen name="collapsed_stack_height">94dp</dimen>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a50a0ac..b3829a3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -553,6 +553,9 @@
         <item quantity="other">%d more</item>
     </plurals>
 
+    <!-- An explanation for the visual speed bump in the notifications, which will appear when you click on it. [CHAR LIMIT=50] -->
+    <string name="speed_bump_explanation">Less urgent notifications below</string>
+
     <!-- Shows to explain the double tap interaction with notifications: After tapping a notification on Keyguard, this will explain users to tap again to launch a notification. [CHAR LIMIT=60] -->
     <string name="notification_tap_again">Tap again to open</string>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 1273e74..9536b12 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -22,8 +22,9 @@
 
     <!-- Alternate Recents theme -->
     <style name="RecentsTheme" parent="@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar">
-        <item name="android:windowTranslucentStatus">true</item>
-        <item name="android:windowTranslucentNavigation">true</item>
+        <item name="android:statusBarColor">@android:color/transparent</item>
+        <item name="android:navigationBarColor">@android:color/transparent</item>
+        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
         <item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
     </style>
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index d32f98f..176e05c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.graphics.drawable.AnimationDrawable;
+
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.LocationController;
@@ -56,16 +58,28 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         final boolean locationEnabled =  mController.isLocationEnabled();
         state.visible = true;
-        state.value = locationEnabled;
-        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_location);
+        if (state.value != locationEnabled) {
+            state.value = locationEnabled;
+            final AnimationDrawable d = (AnimationDrawable) mContext.getDrawable(locationEnabled
+                    ? R.drawable.ic_location_on_anim
+                    : R.drawable.ic_location_off_anim);
+            state.icon = d;
+            mUiHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    d.start();
+                }
+            });
+        }
+        //state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_location);
         if (locationEnabled) {
-            state.iconId = R.drawable.ic_qs_location_on;
+            if (state.icon == null) state.iconId = R.drawable.ic_location_24_01;
             state.label = mContext.getString(R.string.quick_settings_location_label);
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_location,
                     mContext.getString(R.string.accessibility_desc_on));
         } else {
-            state.iconId = R.drawable.ic_qs_location_off;
+            if (state.icon == null) state.iconId = R.drawable.ic_location_24_11;
             state.label = mContext.getString(R.string.quick_settings_location_off_label);
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_location,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 91df9ef..5e8c769 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -21,6 +21,7 @@
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
@@ -45,6 +46,9 @@
     private int mBgResId = R.drawable.notification_quantum_bg;
     private int mDimmedBgResId = R.drawable.notification_quantum_bg_dim;
 
+    private int mBgTint = 0;
+    private int mDimmedBgTint = 0;
+
     /**
      * Flag to indicate that the notification has been touched once and the second touch will
      * click it.
@@ -209,17 +213,23 @@
      * @param bgResId The background resource to use in normal state.
      * @param dimmedBgResId The background resource to use in dimmed state.
      */
-    public void setBackgroundResourceIds(int bgResId, int dimmedBgResId) {
+    public void setBackgroundResourceIds(int bgResId, int bgTint, int dimmedBgResId, int dimmedTint) {
         mBgResId = bgResId;
+        mBgTint = bgTint;
         mDimmedBgResId = dimmedBgResId;
+        mDimmedBgTint = dimmedTint;
         updateBackgroundResource();
     }
 
+    public void setBackgroundResourceIds(int bgResId, int dimmedBgResId) {
+        setBackgroundResourceIds(bgResId, 0, dimmedBgResId, 0);
+    }
+
     private void fadeBackgroundResource() {
         if (mDimmed) {
-            setBackgroundDimmed(mDimmedBgResId);
+            setBackgroundDimmed(mDimmedBgResId, mDimmedBgTint);
         } else {
-            setBackgroundNormal(mBgResId);
+            setBackgroundNormal(mBgResId, mBgTint);
         }
         int startAlpha = mDimmed ? 255 : 0;
         int endAlpha = mDimmed ? 0 : 255;
@@ -256,12 +266,12 @@
 
     private void updateBackgroundResource() {
         if (mDimmed) {
-            setBackgroundDimmed(mDimmedBgResId);
+            setBackgroundDimmed(mDimmedBgResId, mDimmedBgTint);
             mBackgroundDimmed.setAlpha(255);
             setBackgroundNormal(null);
         } else {
             setBackgroundDimmed(null);
-            setBackgroundNormal(mBgResId);
+            setBackgroundNormal(mBgResId, mBgTint);
             mBackgroundNormal.setAlpha(255);
         }
     }
@@ -295,12 +305,20 @@
         invalidate();
     }
 
-    private void setBackgroundNormal(int drawableResId) {
-        setBackgroundNormal(getResources().getDrawable(drawableResId));
+    private void setBackgroundNormal(int drawableResId, int tintColor) {
+        final Drawable d = getResources().getDrawable(drawableResId);
+        if (tintColor != 0) {
+            d.setColorFilter(tintColor, PorterDuff.Mode.SRC_ATOP);
+        }
+        setBackgroundNormal(d);
     }
 
-    private void setBackgroundDimmed(int drawableResId) {
-        setBackgroundDimmed(getResources().getDrawable(drawableResId));
+    private void setBackgroundDimmed(int drawableResId, int tintColor) {
+        final Drawable d = getResources().getDrawable(drawableResId);
+        if (tintColor != 0) {
+            d.setColorFilter(tintColor, PorterDuff.Mode.SRC_ATOP);
+        }
+        setBackgroundDimmed(d);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 898f06e..c1228d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -428,14 +428,16 @@
 
     protected void applyLegacyRowBackground(StatusBarNotification sbn,
             NotificationData.Entry entry) {
+        int version = 0;
+        try {
+            ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(sbn.getPackageName(), 0);
+            version = info.targetSdkVersion;
+        } catch (NameNotFoundException ex) {
+            Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
+        }
+
         if (entry.expanded.getId() != com.android.internal.R.id.status_bar_latest_event_content) {
-            int version = 0;
-            try {
-                ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(sbn.getPackageName(), 0);
-                version = info.targetSdkVersion;
-            } catch (NameNotFoundException ex) {
-                Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
-            }
+            // Using custom RemoteViews
             if (version > 0 && version < Build.VERSION_CODES.GINGERBREAD) {
                 entry.row.setBackgroundResource(R.drawable.notification_row_legacy_bg);
             } else if (version < Build.VERSION_CODES.L) {
@@ -875,6 +877,7 @@
         entry.row = row;
         entry.row.setHeightRange(mRowMinHeight, mRowMaxHeight);
         entry.row.setOnActivatedListener(this);
+        entry.row.setIsBelowSpeedBump(isBelowSpeedBump(entry.notification));
         entry.expanded = contentViewLocal;
         entry.expandedPublic = publicViewLocal;
         entry.setBigContentView(bigContentViewLocal);
@@ -1037,8 +1040,8 @@
         if (DEBUG) {
             Log.d(TAG, "addNotificationViews: added at " + pos);
         }
-        updateRowStates();
         updateNotificationIcons();
+        updateRowStates();
     }
 
     private void addNotificationViews(IBinder key, StatusBarNotification notification) {
@@ -1058,6 +1061,7 @@
         mKeyguardIconOverflowContainer.getIconsView().removeAllViews();
         int n = mNotificationData.size();
         int visibleNotifications = 0;
+        int speedBumpIndex = -1;
         boolean onKeyguard = mState == StatusBarState.KEYGUARD;
         for (int i = n-1; i >= 0; i--) {
             NotificationData.Entry entry = mNotificationData.get(i);
@@ -1085,6 +1089,10 @@
                 entry.row.setVisibility(View.VISIBLE);
                 visibleNotifications++;
             }
+            if (entry.row.getVisibility() != View.GONE && speedBumpIndex == -1
+                    && entry.row.isBelowSpeedBump() ) {
+                speedBumpIndex = n - 1 - i;
+            }
         }
 
         if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
@@ -1092,6 +1100,8 @@
         } else {
             mKeyguardIconOverflowContainer.setVisibility(View.GONE);
         }
+
+        mStackScroller.updateSpeedBumpIndex(speedBumpIndex);
     }
 
     private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
@@ -1307,9 +1317,19 @@
         } else {
             entry.row.setOnClickListener(null);
         }
+        boolean wasBelow = entry.row.isBelowSpeedBump();
+        boolean nowBelow = isBelowSpeedBump(notification);
+        if (wasBelow != nowBelow) {
+            entry.row.setIsBelowSpeedBump(nowBelow);
+        }
         entry.row.notifyContentUpdated();
     }
 
+    private boolean isBelowSpeedBump(StatusBarNotification notification) {
+        return notification.getNotification().priority ==
+                Notification.PRIORITY_MIN;
+    }
+
     protected void notifyHeadsUpScreenOn(boolean screenOn) {
         if (!screenOn && mInterruptingNotificationEntry != null) {
             mHandler.sendEmptyMessage(MSG_ESCALATE_HEADS_UP);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 39f2bb9..f6c80fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -52,6 +52,7 @@
     private NotificationContentView mPublicLayout;
     private NotificationContentView mPrivateLayout;
     private int mMaxExpandHeight;
+    private boolean mIsBelowSpeedBump;
 
     public ExpandableNotificationRow(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -244,6 +245,14 @@
         mPrivateLayout.setClipTopAmount(clipTopAmount);
     }
 
+    public boolean isBelowSpeedBump() {
+        return mIsBelowSpeedBump;
+    }
+
+    public void setIsBelowSpeedBump(boolean isBelow) {
+        this.mIsBelowSpeedBump = isBelow;
+    }
+
     public void notifyContentUpdated() {
         mPrivateLayout.notifyContentUpdated();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 4bd0e1c..061396d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -40,11 +40,15 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         if (!mActualHeightInitialized && mActualHeight == 0) {
-            mActualHeight = getHeight();
+            mActualHeight = getInitialHeight();
         }
         mActualHeightInitialized = true;
     }
 
+    protected int getInitialHeight() {
+        return getHeight();
+    }
+
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
         if (filterMotionEvent(ev)) {
@@ -146,6 +150,10 @@
         }
     }
 
+    public boolean isTransparent() {
+        return false;
+    }
+
     /**
      * A listener notifying when {@link #getActualHeight} changes.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java
new file mode 100644
index 0000000..3ca021a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotView.java
@@ -0,0 +1,47 @@
+/*
+ * 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
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * An single dot of the {@link com.android.systemui.statusbar.SpeedBumpDotsLayout}
+ */
+public class SpeedBumpDotView extends View {
+
+    private final Paint mPaint = new Paint();
+
+    public SpeedBumpDotView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mPaint.setAntiAlias(true);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        float radius = getWidth() / 2.0f;
+        canvas.drawCircle(radius, radius, radius, mPaint);
+    }
+
+    public void setColor(int color) {
+        mPaint.setColor(color);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java
new file mode 100644
index 0000000..cac6327
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsAlgorithm.java
@@ -0,0 +1,80 @@
+/*
+ * 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
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.view.View;
+import com.android.systemui.R;
+
+/**
+ * The Algorithm of the {@link com.android.systemui.statusbar.SpeedBumpDotsLayout} which can be
+ * queried for {@link * com.android.systemui.statusbar.SpeedBumpDotsState}
+ */
+public class SpeedBumpDotsAlgorithm {
+
+    private final float mDotRadius;
+
+    public SpeedBumpDotsAlgorithm(Context context) {
+        mDotRadius = context.getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height)
+                / 2.0f;
+    }
+
+    public void getState(SpeedBumpDotsState resultState) {
+
+        // First reset the current state and ensure that every View has a ViewState
+        resultState.resetViewStates();
+
+        SpeedBumpDotsLayout hostView = resultState.getHostView();
+        boolean currentlyVisible = hostView.isCurrentlyVisible();
+        resultState.setActiveState(currentlyVisible
+                ? SpeedBumpDotsState.SHOWN
+                : SpeedBumpDotsState.HIDDEN);
+        int hostWidth = hostView.getWidth();
+        float layoutWidth = hostWidth - 2 * mDotRadius;
+        int childCount = hostView.getChildCount();
+        float paddingBetween = layoutWidth / (childCount - 1);
+        float centerY = hostView.getHeight() / 2.0f;
+        for (int i = 0; i < childCount; i++) {
+            View child = hostView.getChildAt(i);
+            SpeedBumpDotsState.ViewState viewState = resultState.getViewStateForView(child);
+            if (currentlyVisible) {
+                float xTranslation = i * paddingBetween;
+                viewState.xTranslation = xTranslation;
+                viewState.yTranslation = calculateYTranslation(hostView, centerY, xTranslation,
+                        layoutWidth);
+            } else {
+                viewState.xTranslation = layoutWidth / 2;
+                viewState.yTranslation = centerY - mDotRadius;
+            }
+            viewState.alpha = currentlyVisible ? 1.0f : 0.0f;
+            viewState.scale = currentlyVisible ? 1.0f : 0.5f;
+        }
+    }
+
+    private float calculateYTranslation(SpeedBumpDotsLayout hostView, float centerY,
+            float xTranslation, float layoutWidth) {
+        float t = hostView.getAnimationProgress();
+        if (t == 0.0f || t == 1.0f) {
+            return centerY - mDotRadius;
+        }
+        float damping = (0.5f -Math.abs(0.5f - t)) * 1.3f;
+        float partialOffset = xTranslation / layoutWidth;
+        float indentFactor = (float) (Math.sin((t + partialOffset * 1.5f) * - Math.PI) * damping);
+        return (1.0f - indentFactor) * centerY - mDotRadius;
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java
new file mode 100644
index 0000000..ddf5215
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsLayout.java
@@ -0,0 +1,136 @@
+/*
+ * 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
+ */
+
+package com.android.systemui.statusbar;
+
+import android.animation.TimeAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import com.android.systemui.R;
+
+/**
+ * A layout with a certain number of dots which are integrated in the
+ * {@link com.android.systemui.statusbar.SpeedBumpView}
+ */
+public class SpeedBumpDotsLayout extends ViewGroup {
+
+    private static final float DOT_CLICK_ANIMATION_LENGTH = 300;
+    private final int mDotSize;
+    private final SpeedBumpDotsAlgorithm mAlgorithm = new SpeedBumpDotsAlgorithm(getContext());
+    private final SpeedBumpDotsState mCurrentState = new SpeedBumpDotsState(this);
+    private boolean mIsCurrentlyVisible = true;
+    private final ValueAnimator mClickAnimator;
+    private float mAnimationProgress;
+    private ValueAnimator.AnimatorUpdateListener mClickUpdateListener
+            = new ValueAnimator.AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            mAnimationProgress = animation.getAnimatedFraction();
+            updateChildren();
+        }
+    };
+
+    public SpeedBumpDotsLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mDotSize = getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height);
+        createDots(context, attrs);
+        mClickAnimator = TimeAnimator.ofFloat(0, DOT_CLICK_ANIMATION_LENGTH);
+        mClickAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
+        mClickAnimator.addUpdateListener(mClickUpdateListener);
+    }
+
+    private void createDots(Context context, AttributeSet attrs) {
+        SpeedBumpDotView blueDot = new SpeedBumpDotView(context, attrs);
+        blueDot.setColor(getResources().getColor(R.color.speed_bump_dot_blue));
+        addView(blueDot);
+
+        SpeedBumpDotView redDot = new SpeedBumpDotView(context, attrs);
+        redDot.setColor(getResources().getColor(R.color.speed_bump_dot_red));
+        addView(redDot);
+
+        SpeedBumpDotView yellowDot = new SpeedBumpDotView(context, attrs);
+        yellowDot.setColor(getResources().getColor(R.color.speed_bump_dot_yellow));
+        addView(yellowDot);
+
+        SpeedBumpDotView greenDot = new SpeedBumpDotView(context, attrs);
+        greenDot.setColor(getResources().getColor(R.color.speed_bump_dot_green));
+        addView(greenDot);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        int childWidthSpec = MeasureSpec.makeMeasureSpec(mDotSize,
+                MeasureSpec.getMode(widthMeasureSpec));
+        int childHeightSpec = MeasureSpec.makeMeasureSpec(mDotSize,
+                MeasureSpec.getMode(heightMeasureSpec));
+        measureChildren(childWidthSpec, childHeightSpec);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            child.layout(0, 0, mDotSize, mDotSize);
+        }
+        if (changed) {
+            updateChildren();
+        }
+    }
+
+    private void updateChildren() {
+        mAlgorithm.getState(mCurrentState);
+        mCurrentState.apply();
+    }
+
+    public void performVisibilityAnimation(boolean visible) {
+        if (mClickAnimator.isRunning()) {
+            mClickAnimator.cancel();
+        }
+        mIsCurrentlyVisible = visible;
+        mAlgorithm.getState(mCurrentState);
+        mCurrentState.animateToState();
+    }
+
+    public void setInvisible() {
+        mIsCurrentlyVisible = false;
+        mAlgorithm.getState(mCurrentState);
+        mCurrentState.apply();
+    }
+
+    public boolean isCurrentlyVisible() {
+        return mIsCurrentlyVisible;
+    }
+
+    public void performDotClickAnimation() {
+        if (mClickAnimator.isRunning()) {
+            // don't perform an animation if it's running already
+            return;
+        }
+        mClickAnimator.start();
+    }
+
+
+    public float getAnimationProgress() {
+        return mAnimationProgress;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java
new file mode 100644
index 0000000..06a7f95
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpDotsState.java
@@ -0,0 +1,139 @@
+/*
+ * 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
+ */
+
+package com.android.systemui.statusbar;
+
+import android.view.View;
+import android.view.ViewPropertyAnimator;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A state of a {@link com.android.systemui.statusbar.SpeedBumpDotsLayout}
+ */
+public class SpeedBumpDotsState {
+
+    public static final int HIDDEN = 1;
+    public static final int SHOWN = 2;
+    private static final int VISIBILITY_ANIMATION_DELAY_PER_ELEMENT = 80;
+
+    private final SpeedBumpDotsLayout mHostView;
+    private final HashMap<View, ViewState> mStateMap = new HashMap<View, ViewState>();
+    private final Interpolator mFastOutSlowInInterpolator;
+    private int mActiveState = 0;
+
+    public SpeedBumpDotsState(SpeedBumpDotsLayout hostLayout) {
+        mHostView = hostLayout;
+        mFastOutSlowInInterpolator = AnimationUtils
+                .loadInterpolator(hostLayout.getContext(),
+                        android.R.interpolator.fast_out_slow_in);
+    }
+
+    public SpeedBumpDotsLayout getHostView() {
+        return mHostView;
+    }
+
+    public void resetViewStates() {
+        int numChildren = mHostView.getChildCount();
+        for (int i = 0; i < numChildren; i++) {
+            View child = mHostView.getChildAt(i);
+            ViewState viewState = mStateMap.get(child);
+            if (viewState == null) {
+                viewState = new ViewState();
+                mStateMap.put(child, viewState);
+            }
+        }
+    }
+
+    public ViewState getViewStateForView(View requestedView) {
+        return mStateMap.get(requestedView);
+    }
+
+    public void apply() {
+        int childCount = mHostView.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = mHostView.getChildAt(i);
+            ViewState viewState = mStateMap.get(child);
+            float translationX = child.getTranslationX();
+            float translationY = child.getTranslationY();
+            float scale = child.getScaleX();
+            float alpha = child.getAlpha();
+            if (translationX != viewState.xTranslation) {
+                child.setTranslationX(viewState.xTranslation);
+            }
+            if (translationY != viewState.yTranslation) {
+                child.setTranslationY(viewState.yTranslation);
+            }
+            if (scale != viewState.scale) {
+                child.setScaleX(viewState.scale);
+                child.setScaleY(viewState.scale);
+            }
+            if (alpha != viewState.alpha) {
+                child.setAlpha(viewState.alpha);
+            }
+        }
+    }
+
+    public void animateToState() {
+        int childCount = mHostView.getChildCount();
+        int middleIndex = (childCount - 1) / 2;
+        long delayPerElement = VISIBILITY_ANIMATION_DELAY_PER_ELEMENT;
+        boolean isAppearing = getActiveState() == SHOWN;
+        boolean isDisappearing = getActiveState() == HIDDEN;
+        for (int i = 0; i < childCount; i++) {
+            int delayIndex;
+            if (i <= middleIndex) {
+                delayIndex = i * 2;
+            } else {
+                int distToMiddle = i - middleIndex;
+                delayIndex = (childCount - 1) - (distToMiddle - 1) * 2;
+            }
+            long startDelay = 0;
+            if (isAppearing || isDisappearing) {
+                if (isDisappearing) {
+                    delayIndex = childCount - 1 - delayIndex;
+                }
+                startDelay = delayIndex * delayPerElement;
+            }
+            View child = mHostView.getChildAt(i);
+            ViewState viewState = mStateMap.get(child);
+            child.animate().setInterpolator(mFastOutSlowInInterpolator)
+                    .setStartDelay(startDelay)
+                    .alpha(viewState.alpha).withLayer()
+                    .translationX(viewState.xTranslation)
+                    .translationY(viewState.yTranslation)
+                    .scaleX(viewState.scale).scaleY(viewState.scale);
+        }
+    }
+
+    public int getActiveState() {
+        return mActiveState;
+    }
+
+    public void setActiveState(int mActiveState) {
+        this.mActiveState = mActiveState;
+    }
+
+    public static class ViewState {
+        float xTranslation;
+        float yTranslation;
+        float alpha;
+        float scale;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
new file mode 100644
index 0000000..8ae503a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
@@ -0,0 +1,265 @@
+/*
+ * 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
+ */
+
+package com.android.systemui.statusbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Outline;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.TextView;
+import com.android.systemui.R;
+
+/**
+ * The view representing the separation between important and less important notifications
+ */
+public class SpeedBumpView extends ExpandableView implements View.OnClickListener {
+
+    private final int mCollapsedHeight;
+    private final int mDotsHeight;
+    private final int mTextPaddingInset;
+    private SpeedBumpDotsLayout mDots;
+    private View mLineLeft;
+    private View mLineRight;
+    private boolean mIsExpanded;
+    private boolean mDividerVisible = true;
+    private ValueAnimator mCurrentAnimator;
+    private final Interpolator mFastOutSlowInInterpolator;
+    private float mCenterX;
+    private TextView mExplanationText;
+    private boolean mExplanationTextVisible = false;
+    private AnimatorListenerAdapter mHideExplanationListener = new AnimatorListenerAdapter() {
+        private boolean mCancelled;
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (!mCancelled) {
+                mExplanationText.setVisibility(View.INVISIBLE);
+            }
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mCancelled = true;
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            mCancelled = false;
+        }
+    };
+    private Animator.AnimatorListener mAnimationFinishedListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mCurrentAnimator = null;
+        }
+    };
+
+    public SpeedBumpView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mCollapsedHeight = getResources()
+                .getDimensionPixelSize(R.dimen.speed_bump_height_collapsed);
+        mTextPaddingInset = getResources().getDimensionPixelSize(
+                R.dimen.speed_bump_text_padding_inset);
+        mDotsHeight = getResources().getDimensionPixelSize(R.dimen.speed_bump_dots_height);
+        setOnClickListener(this);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
+                android.R.interpolator.fast_out_slow_in);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mDots = (SpeedBumpDotsLayout) findViewById(R.id.speed_bump_dots_layout);
+        mLineLeft = findViewById(R.id.speedbump_line_left);
+        mLineRight = findViewById(R.id.speedbump_line_right);
+        mExplanationText = (TextView) findViewById(R.id.speed_bump_text);
+        resetExplanationText();
+
+    }
+
+    @Override
+    protected int getInitialHeight() {
+        return mCollapsedHeight;
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return getActualHeight();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        Outline outline = new Outline();
+        mCenterX = getWidth() / 2;
+        float centerY = getHeight() / 2;
+        // TODO: hide outline better
+        // Temporary workaround to hide outline on a transparent view
+        int outlineLeft = (int) (mCenterX - getResources().getDisplayMetrics().densityDpi * 8);
+        int outlineTop = (int) (centerY - mDotsHeight / 2);
+        outline.setOval(outlineLeft, outlineTop, outlineLeft + mDotsHeight,
+                outlineTop + mDotsHeight);
+        setOutline(outline);
+        mLineLeft.setPivotX(mLineLeft.getWidth());
+        mLineLeft.setPivotY(mLineLeft.getHeight() / 2);
+        mLineRight.setPivotX(0);
+        mLineRight.setPivotY(mLineRight.getHeight() / 2);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        measureChildren(widthMeasureSpec, heightMeasureSpec);
+        int height = mCollapsedHeight + mExplanationText.getMeasuredHeight() - mTextPaddingInset;
+        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (mCurrentAnimator != null) {
+            return;
+        }
+        int startValue = mIsExpanded ? getMaxHeight() : mCollapsedHeight;
+        int endValue = mIsExpanded ? mCollapsedHeight : getMaxHeight();
+        mCurrentAnimator = ValueAnimator.ofInt(startValue, endValue);
+        mCurrentAnimator.setInterpolator(mFastOutSlowInInterpolator);
+        mCurrentAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                setActualHeight((int) animation.getAnimatedValue());
+            }
+        });
+        mCurrentAnimator.addListener(mAnimationFinishedListener);
+        mCurrentAnimator.start();
+        mIsExpanded = !mIsExpanded;
+        mDots.performDotClickAnimation();
+        animateExplanationTextInternal(mIsExpanded);
+    }
+
+    private void animateExplanationTextInternal(boolean visible) {
+        if (mExplanationTextVisible != visible) {
+            float translationY = 0.0f;
+            float scale = 0.5f;
+            float alpha = 0.0f;
+            boolean needsHideListener = true;
+            if (visible) {
+                mExplanationText.setVisibility(VISIBLE);
+                translationY = mDots.getBottom() - mTextPaddingInset;
+                scale = 1.0f;
+                alpha = 1.0f;
+                needsHideListener = false;
+            }
+            mExplanationText.animate().setInterpolator(mFastOutSlowInInterpolator)
+                    .alpha(alpha)
+                    .scaleX(scale)
+                    .scaleY(scale)
+                    .translationY(translationY)
+                    .setListener(needsHideListener ? mHideExplanationListener : null)
+                    .withLayer();
+            mExplanationTextVisible = visible;
+        }
+    }
+
+    @Override
+    public boolean isTransparent() {
+        return true;
+    }
+
+    public void performVisibilityAnimation(boolean nowVisible) {
+        animateDivider(nowVisible);
+
+        // Animate explanation Text
+        if (mIsExpanded) {
+            animateExplanationTextInternal(nowVisible);
+        }
+    }
+
+    public void animateDivider(boolean nowVisible) {
+        if (nowVisible != mDividerVisible) {
+            // Animate dividers
+            float endValue = nowVisible ? 1.0f : 0.0f;
+            float endTranslationXLeft = nowVisible ? 0.0f : mCenterX - mLineLeft.getRight();
+            float endTranslationXRight = nowVisible ? 0.0f : mCenterX - mLineRight.getLeft();
+            mLineLeft.animate()
+                    .alpha(endValue)
+                    .withLayer()
+                    .scaleX(endValue)
+                    .scaleY(endValue)
+                    .translationX(endTranslationXLeft)
+                    .setInterpolator(mFastOutSlowInInterpolator);
+            mLineRight.animate()
+                    .alpha(endValue)
+                    .withLayer()
+                    .scaleX(endValue)
+                    .scaleY(endValue)
+                    .translationX(endTranslationXRight)
+                    .setInterpolator(mFastOutSlowInInterpolator);
+
+            // Animate dots
+            mDots.performVisibilityAnimation(nowVisible);
+            mDividerVisible = nowVisible;
+        }
+    }
+
+    public void setInvisible() {
+        float endTranslationXLeft = mCenterX - mLineLeft.getRight();
+        float endTranslationXRight = mCenterX - mLineRight.getLeft();
+        mLineLeft.setAlpha(0.0f);
+        mLineLeft.setScaleX(0.0f);
+        mLineLeft.setScaleY(0.0f);
+        mLineLeft.setTranslationX(endTranslationXLeft);
+        mLineRight.setAlpha(0.0f);
+        mLineRight.setScaleX(0.0f);
+        mLineRight.setScaleY(0.0f);
+        mLineRight.setTranslationX(endTranslationXRight);
+        mDots.setInvisible();
+        resetExplanationText();
+
+        mDividerVisible = false;
+    }
+
+    public void collapse() {
+        if (mIsExpanded) {
+            setActualHeight(mCollapsedHeight);
+            mIsExpanded = false;
+        }
+        resetExplanationText();
+    }
+
+    public void animateExplanationText(boolean nowVisible) {
+        if (mIsExpanded) {
+            animateExplanationTextInternal(nowVisible);
+        }
+    }
+
+    private void resetExplanationText() {
+        mExplanationText.setTranslationY(0);
+        mExplanationText.setVisibility(INVISIBLE);
+        mExplanationText.setAlpha(0.0f);
+        mExplanationText.setScaleX(0.5f);
+        mExplanationText.setScaleY(0.5f);
+        mExplanationTextVisible = false;
+    }
+
+    public boolean isExpanded() {
+        return mIsExpanded;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index eb63a54..a41ec22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -43,6 +43,7 @@
     public static final int MODE_SEMI_TRANSPARENT = 1;
     public static final int MODE_TRANSLUCENT = 2;
     public static final int MODE_LIGHTS_OUT = 3;
+    public static final int MODE_TRANSPARENT = 4;
 
     public static final int LIGHTS_IN_DURATION = 250;
     public static final int LIGHTS_OUT_DURATION = 750;
@@ -69,7 +70,8 @@
 
     public void transitionTo(int mode, boolean animate) {
         // low-end devices do not support translucent modes, fallback to opaque
-        if (!HIGH_END && (mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT)) {
+        if (!HIGH_END && (mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT
+                || mode == MODE_TRANSPARENT)) {
             mode = MODE_OPAQUE;
         }
         if (mMode == mode) return;
@@ -97,6 +99,7 @@
         if (mode == MODE_SEMI_TRANSPARENT) return "MODE_SEMI_TRANSPARENT";
         if (mode == MODE_TRANSLUCENT) return "MODE_TRANSLUCENT";
         if (mode == MODE_LIGHTS_OUT) return "MODE_LIGHTS_OUT";
+        if (mode == MODE_TRANSPARENT) return "MODE_TRANSPARENT";
         throw new IllegalArgumentException("Unknown mode " + mode);
     }
 
@@ -111,6 +114,7 @@
     private static class BarBackgroundDrawable extends Drawable {
         private final int mOpaque;
         private final int mSemiTransparent;
+        private final int mTransparent;
         private final Drawable mGradient;
         private final TimeInterpolator mInterpolator;
 
@@ -130,9 +134,11 @@
             if (DEBUG_COLORS) {
                 mOpaque = 0xff0000ff;
                 mSemiTransparent = 0x7f0000ff;
+                mTransparent = 0x2f0000ff;
             } else {
                 mOpaque = res.getColor(R.color.system_bar_background_opaque);
                 mSemiTransparent = res.getColor(R.color.system_bar_background_semi_transparent);
+                mTransparent = res.getColor(R.color.system_bar_background_transparent);
             }
             mGradient = res.getDrawable(gradientResourceId);
             mInterpolator = new LinearInterpolator();
@@ -184,9 +190,11 @@
         public void draw(Canvas canvas) {
             int targetGradientAlpha = 0, targetColor = 0;
             if (mMode == MODE_TRANSLUCENT) {
-                targetGradientAlpha = 0xff;
+                targetColor = mSemiTransparent;
             } else if (mMode == MODE_SEMI_TRANSPARENT) {
                 targetColor = mSemiTransparent;
+            } else if (mMode == MODE_TRANSPARENT) {
+                targetColor = mTransparent;
             } else {
                 targetColor = mOpaque;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index a0582ee..c83b479 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -61,7 +61,7 @@
     @Override
     public void transitionTo(int mode, boolean animate) {
         mRequestedMode = mode;
-        if (mVertical && mode == MODE_TRANSLUCENT) {
+        if (mVertical && (mode == MODE_TRANSLUCENT || mode == MODE_TRANSPARENT)) {
             // translucent mode not allowed when vertical
             mode = MODE_OPAQUE;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index b9f5ab2..cd985f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -143,8 +143,9 @@
         }
     }
 
-    public void animateNextTopPaddingChange() {
+    public void animateToFullShade() {
         mAnimateNextTopPaddingChange = true;
+        mNotificationStackScroller.goToFullShade();
         requestLayout();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 8c70517..dde2ebb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -20,6 +20,7 @@
 import android.animation.TimeAnimator;
 import android.animation.TimeAnimator.TimeListener;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -218,7 +219,7 @@
     };
 
     private float mVel, mAccel;
-    protected int mMaxPanelHeight = 0;
+    protected int mMaxPanelHeight = -1;
     private String mViewName;
     private float mInitialTouchY;
     private float mInitialTouchX;
@@ -617,7 +618,8 @@
 
         // Did one of our children change size?
         int newHeight = getMeasuredHeight();
-        if (newHeight != mMaxPanelHeight) {
+        if (newHeight > mMaxPanelHeight) {
+            // we only adapt the max height if it's bigger
             mMaxPanelHeight = newHeight;
             // If the user isn't actively poking us, let's rubberband to the content
             if (!mTracking && !mTimeAnimator.isStarted()
@@ -695,6 +697,12 @@
         mExpandedFraction = Math.min(1f, (fh == 0) ? 0 : h / fh);
     }
 
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        mMaxPanelHeight = -1;
+    }
+
     protected void onHeightUpdated(float expandedHeight) {
         requestLayout();
     }
@@ -706,6 +714,7 @@
      * @return the default implementation simply returns the maximum height.
      */
     protected int getMaxPanelHeight() {
+        mMaxPanelHeight = Math.max(mMaxPanelHeight, getHeight());
         return mMaxPanelHeight;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 23b0594..4e1ffa5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -26,6 +26,7 @@
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_OPAQUE;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCENT;
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -105,6 +106,7 @@
 import com.android.systemui.statusbar.NotificationData.Entry;
 import com.android.systemui.statusbar.NotificationOverflowContainer;
 import com.android.systemui.statusbar.SignalClusterView;
+import com.android.systemui.statusbar.SpeedBumpView;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -633,6 +635,10 @@
         mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
         mStackScroller.addView(mKeyguardIconOverflowContainer);
 
+        SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate(
+                        R.layout.status_bar_notification_speed_bump, mStackScroller, false);
+        mStackScroller.setSpeedBumpView(speedBump);
+
         mExpandedContents = mStackScroller;
 
         mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
@@ -1149,7 +1155,7 @@
         ArrayList<View> toRemove = new ArrayList<View>();
         for (int i=0; i< mStackScroller.getChildCount(); i++) {
             View child = mStackScroller.getChildAt(i);
-            if (!toShow.contains(child) && child != mKeyguardIconOverflowContainer) {
+            if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {
                 toRemove.add(child);
             }
         }
@@ -1870,6 +1876,7 @@
     private int barMode(int vis, int transientFlag, int translucentFlag) {
         return (vis & transientFlag) != 0 ? MODE_SEMI_TRANSPARENT
                 : (vis & translucentFlag) != 0 ? MODE_TRANSLUCENT
+                : (vis & View.SYSTEM_UI_TRANSPARENT) != 0 ? MODE_TRANSPARENT
                 : (vis & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0 ? MODE_LIGHTS_OUT
                 : MODE_OPAQUE;
     }
@@ -2720,7 +2727,7 @@
         setBarState(StatusBarState.SHADE);
         if (mLeaveOpenOnKeyguardHide) {
             mLeaveOpenOnKeyguardHide = false;
-            mNotificationPanel.animateNextTopPaddingChange();
+            mNotificationPanel.animateToFullShade();
         } else {
             instantCollapseNotificationPanel();
         }
@@ -2892,7 +2899,7 @@
             mLeaveOpenOnKeyguardHide = true;
             showBouncer();
         } else {
-            mNotificationPanel.animateNextTopPaddingChange();
+            mNotificationPanel.animateToFullShade();
             setBarState(StatusBarState.SHADE_LOCKED);
             updateKeyguardState();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
index 8406565..8520f40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -68,7 +68,8 @@
     }
 
     private boolean isOpaque(int mode) {
-        return !(mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT);
+        return !(mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT
+                || mode == MODE_TRANSPARENT);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 46a637b..b7bf6cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -75,8 +75,7 @@
                         | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                         | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                         | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                        | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
-                        | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
+                        | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                 PixelFormat.TRANSLUCENT);
         mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         mLp.gravity = Gravity.TOP;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index deab757..b21e12c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -30,6 +30,7 @@
     private View mActivatedChild;
     private float mOverScrollTopAmount;
     private float mOverScrollBottomAmount;
+    private int mSpeedBumpIndex = -1;
 
     public int getScrollY() {
         return mScrollY;
@@ -86,4 +87,12 @@
     public float getOverScrollAmount(boolean top) {
         return top ? mOverScrollTopAmount : mOverScrollBottomAmount;
     }
+
+    public int getSpeedBumpIndex() {
+        return mSpeedBumpIndex;
+    }
+
+    public void setSpeedBumpIndex(int speedBumpIndex) {
+        mSpeedBumpIndex = speedBumpIndex;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index fbb6695..f125c9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -39,6 +39,7 @@
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.SpeedBumpView;
 import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
 import com.android.systemui.statusbar.policy.ScrollAdapter;
 
@@ -126,6 +127,8 @@
     private boolean mActivateNeedsAnimation;
     private boolean mIsExpanded = true;
     private boolean mChildrenUpdateRequested;
+    private SpeedBumpView mSpeedBumpView;
+    private boolean mIsExpansionChanging;
     private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
             = new ViewTreeObserver.OnPreDrawListener() {
         @Override
@@ -244,6 +247,22 @@
         requestChildrenUpdate();
     }
 
+    public void updateSpeedBumpIndex(int newIndex) {
+        int currentIndex = indexOfChild(mSpeedBumpView);
+
+        // If we are currently layouted before the new speed bump index, we have to decrease it.
+        boolean validIndex = newIndex > 0;
+        if (newIndex > getChildCount() - 1) {
+            validIndex = false;
+            newIndex = -1;
+        }
+        if (validIndex && currentIndex != newIndex) {
+            changeViewPosition(mSpeedBumpView, newIndex);
+        }
+        updateSpeedBump(validIndex);
+        mAmbientState.setSpeedBumpIndex(newIndex);
+    }
+
     public void setChildLocationsChangedListener(OnChildLocationsChangedListener listener) {
         mListener = listener;
     }
@@ -1044,6 +1063,10 @@
         mCurrentStackScrollState.removeViewStateForView(child);
         mStackScrollAlgorithm.notifyChildrenChanged(this);
         updateScrollStateForRemovedChild(child);
+        generateRemoveAnimation(child);
+    }
+
+    private void generateRemoveAnimation(View child) {
         if (mIsExpanded) {
 
             if (!mChildrenToAddAnimated.contains(child)) {
@@ -1120,7 +1143,9 @@
      */
     public void changeViewPosition(View child, int newIndex) {
         if (child != null && child.getParent() == this) {
-            // TODO: handle this
+            removeView(child);
+            addView(child, newIndex);
+            // TODO: handle events
         }
     }
 
@@ -1362,10 +1387,12 @@
     }
 
     public void onExpansionStarted() {
+        mIsExpansionChanging = true;
         mStackScrollAlgorithm.onExpansionStarted(mCurrentStackScrollState);
     }
 
     public void onExpansionStopped() {
+        mIsExpansionChanging = false;
         mStackScrollAlgorithm.onExpansionStopped();
     }
 
@@ -1374,6 +1401,7 @@
         mStackScrollAlgorithm.setIsExpanded(isExpanded);
         if (!isExpanded) {
             mOwnScrollY = 0;
+            mSpeedBumpView.collapse();
         }
     }
 
@@ -1432,6 +1460,34 @@
         }
     }
 
+    public void setSpeedBumpView(SpeedBumpView speedBumpView) {
+        mSpeedBumpView = speedBumpView;
+        addView(speedBumpView);
+    }
+
+    private void updateSpeedBump(boolean visible) {
+        int newVisibility = visible ? VISIBLE : GONE;
+        int oldVisibility = mSpeedBumpView.getVisibility();
+        if (newVisibility != oldVisibility) {
+            mSpeedBumpView.setVisibility(newVisibility);
+            if (visible) {
+                mSpeedBumpView.collapse();
+                // Make invisible to ensure that the appear animation is played.
+                mSpeedBumpView.setInvisible();
+                if (!mIsExpansionChanging) {
+                    generateAddAnimation(mSpeedBumpView);
+                }
+            } else {
+                mSpeedBumpView.performVisibilityAnimation(false);
+                generateRemoveAnimation(mSpeedBumpView);
+            }
+        }
+    }
+
+    public void goToFullShade() {
+        updateSpeedBump(true);
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 8fc26d8..011411c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -23,6 +23,7 @@
 import android.view.ViewGroup;
 
 import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.SpeedBumpView;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -167,13 +168,50 @@
                         clipHeight,
                         (int) (newHeight - (previousNotificationStart - newYTranslation)));
 
-                previousNotificationStart = newYTranslation + child.getClipTopAmount();
-                previousNotificationEnd = newNotificationEnd;
-                previousNotificationIsSwiped = child.getTranslationX() != 0;
+                if (!child.isTransparent()) {
+                    // Only update the previous values if we are not transparent,
+                    // otherwise we would clip to a transparent view.
+                    previousNotificationStart = newYTranslation + child.getClipTopAmount();
+                    previousNotificationEnd = newNotificationEnd;
+                    previousNotificationIsSwiped = child.getTranslationX() != 0;
+                }
+
+                if(child instanceof SpeedBumpView) {
+                    performSpeedBumpAnimation(i, (SpeedBumpView) child, newNotificationEnd,
+                            newYTranslation);
+                }
             }
         }
     }
 
+    private void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, float speedBumpEnd,
+            float speedBumpStart) {
+        View nextChild = getNextChildNotGone(i);
+        if (nextChild != null) {
+            ViewState nextState = getViewStateForView(nextChild);
+            boolean startIsAboveNext = nextState.yTranslation > speedBumpStart;
+            speedBump.animateDivider(startIsAboveNext);
+
+            // handle expanded case
+            if (speedBump.isExpanded()) {
+                boolean endIsAboveNext = nextState.yTranslation > speedBumpEnd;
+                speedBump.animateExplanationText(endIsAboveNext);
+            }
+
+        }
+    }
+
+    private View getNextChildNotGone(int childIndex) {
+        int childCount = mHostView.getChildCount();
+        for (int i = childIndex + 1; i < childCount; i++) {
+            View child = mHostView.getChildAt(i);
+            if (child.getVisibility() != View.GONE) {
+                return child;
+            }
+        }
+        return null;
+    }
+
     /**
      * Updates the shadow outline and the clipping for a view.
      *
diff --git a/policy/src/com/android/internal/policy/impl/BarController.java b/policy/src/com/android/internal/policy/impl/BarController.java
index fc49a569..49e1072 100644
--- a/policy/src/com/android/internal/policy/impl/BarController.java
+++ b/policy/src/com/android/internal/policy/impl/BarController.java
@@ -108,13 +108,20 @@
         if (mWin != null) {
             if (win != null && (win.getAttrs().privateFlags
                     & WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) {
-                if ((PolicyControl.getWindowFlags(win, null) & mTranslucentWmFlag) != 0) {
+                int fl = PolicyControl.getWindowFlags(win, null);
+                if ((fl & mTranslucentWmFlag) != 0) {
                     vis |= mTranslucentFlag;
                 } else {
                     vis &= ~mTranslucentFlag;
                 }
+                if ((fl & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
+                    vis |= View.SYSTEM_UI_TRANSPARENT;
+                } else {
+                    vis &= ~View.SYSTEM_UI_TRANSPARENT;
+                }
             } else {
                 vis = (vis & ~mTranslucentFlag) | (oldVis & mTranslucentFlag);
+                vis = (vis & View.SYSTEM_UI_TRANSPARENT) | (oldVis & View.SYSTEM_UI_TRANSPARENT);
             }
         }
         return vis;
@@ -230,7 +237,8 @@
             vis |= mTransientFlag;  // ignore clear requests until transition completes
             vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE;  // never show transient bars in low profile
         }
-        if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0) {
+        if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0 ||
+                ((vis | oldVis) & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0) {
             mLastTranslucent = SystemClock.uptimeMillis();
         }
         return vis;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 6341a0c..1b96f1f 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -38,9 +38,7 @@
 import com.android.internal.widget.ActionBarView;
 import com.android.internal.widget.SwipeDismissLayout;
 
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.app.ActivityOptions;
+import android.app.ActivityManager;
 import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -49,6 +47,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -56,22 +55,15 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.transition.ChangeBounds;
-import android.transition.Explode;
-import android.transition.Fade;
-import android.transition.MoveImage;
 import android.transition.Scene;
 import android.transition.Transition;
 import android.transition.TransitionInflater;
 import android.transition.TransitionManager;
-import android.transition.TransitionSet;
 import android.util.AndroidRuntimeException;
-import android.util.ArrayMap;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
@@ -98,7 +90,6 @@
 import android.view.ViewParent;
 import android.view.ViewRootImpl;
 import android.view.ViewStub;
-import android.view.ViewTreeObserver;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
@@ -113,8 +104,6 @@
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
 
 /**
  * Android-specific Window.
@@ -213,6 +202,8 @@
     private int mFrameResource = 0;
 
     private int mTextColor = 0;
+    private int mStatusBarColor = 0;
+    private int mNavigationBarColor = 0;
 
     private CharSequence mTitle = null;
 
@@ -1987,7 +1978,8 @@
         }
     }
 
-    private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
+    private final class DecorView extends FrameLayout implements RootViewSurfaceTaker,
+            View.OnSystemUiVisibilityChangeListener {
         /* package */int mDefaultOpacity = PixelFormat.OPAQUE;
 
         /** The feature ID of the panel, or -1 if this is the application's DecorView */
@@ -2017,6 +2009,14 @@
         // View added at runtime to draw under the navigation bar area
         private View mNavigationGuard;
 
+        private View mStatusColorView;
+        private View mNavigationColorView;
+
+        private int mLastTopInset = 0;
+        private int mLastBottomInset = 0;
+        private int mLastSystemUiVisibility = 0;
+
+
         public DecorView(Context context, int featureId) {
             super(context);
             mFeatureId = featureId;
@@ -2582,8 +2582,15 @@
         }
 
         @Override
+        public void onSystemUiVisibilityChange(int visible) {
+            mLastSystemUiVisibility = visible;
+            updateColorViews(null /* insets */);
+        }
+
+        @Override
         protected boolean fitSystemWindows(Rect insets) {
             mFrameOffsets.set(insets);
+            updateColorViews(insets);
             updateStatusGuard(insets);
             updateNavigationGuard(insets);
             if (getForeground() != null) {
@@ -2597,6 +2604,52 @@
             return false;
         }
 
+        private void updateColorViews(Rect insets) {
+            if (mIsFloating || !ActivityManager.isHighEndGfx()) {
+                // No colors on floating windows or low end devices :(
+                return;
+            }
+            if (insets != null) {
+                mLastTopInset = insets.top;
+                mLastBottomInset = insets.bottom;
+            }
+            mStatusColorView = updateColorViewInt(mStatusColorView,
+                    SYSTEM_UI_FLAG_FULLSCREEN, FLAG_TRANSLUCENT_STATUS,
+                    mStatusBarColor, mLastTopInset, Gravity.TOP);
+            mNavigationColorView = updateColorViewInt(mNavigationColorView,
+                    SYSTEM_UI_FLAG_HIDE_NAVIGATION, FLAG_TRANSLUCENT_NAVIGATION,
+                    mNavigationBarColor, mLastBottomInset, Gravity.BOTTOM);
+        }
+
+        private View updateColorViewInt(View view, int systemUiHideFlag, int translucentFlag,
+                int color, int height, int verticalGravity) {
+            boolean show = height > 0 && (mLastSystemUiVisibility & systemUiHideFlag) == 0
+                    && (getAttributes().flags & translucentFlag) == 0
+                    && (color & Color.BLACK) != 0
+                    && (getAttributes().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
+
+            if (view == null) {
+                if (show) {
+                    view = new View(mContext);
+                    view.setBackgroundColor(color);
+                    addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, height,
+                            Gravity.START | verticalGravity));
+                }
+            } else {
+                int vis = show ? VISIBLE : INVISIBLE;
+                view.setVisibility(vis);
+                if (show) {
+                    LayoutParams lp = (LayoutParams) view.getLayoutParams();
+                    if (lp.height != height) {
+                        lp.height = height;
+                        view.setLayoutParams(lp);
+                    }
+                    view.setBackgroundColor(color);
+                }
+            }
+            return view;
+        }
+
         private void updateStatusGuard(Rect insets) {
             boolean showStatusGuard = false;
             // Show the status guard when the non-overlay contextual action bar is showing
@@ -2616,9 +2669,9 @@
                                 mStatusGuard = new View(mContext);
                                 mStatusGuard.setBackgroundColor(mContext.getResources()
                                         .getColor(R.color.input_method_navigation_guard));
-                                addView(mStatusGuard, new LayoutParams(
-                                        LayoutParams.MATCH_PARENT, mlp.topMargin,
-                                        Gravity.START | Gravity.TOP));
+                                addView(mStatusGuard, indexOfChild(mStatusColorView),
+                                        new LayoutParams(LayoutParams.MATCH_PARENT, mlp.topMargin,
+                                                Gravity.START | Gravity.TOP));
                             } else {
                                 LayoutParams lp = (LayoutParams) mStatusGuard.getLayoutParams();
                                 if (lp.height != mlp.topMargin) {
@@ -2663,7 +2716,7 @@
                     mNavigationGuard = new View(mContext);
                     mNavigationGuard.setBackgroundColor(mContext.getResources()
                             .getColor(R.color.input_method_navigation_guard));
-                    addView(mNavigationGuard, new LayoutParams(
+                    addView(mNavigationGuard, indexOfChild(mNavigationColorView), new LayoutParams(
                             LayoutParams.MATCH_PARENT, insets.bottom,
                             Gravity.START | Gravity.BOTTOM));
                 } else {
@@ -3009,6 +3062,7 @@
         final int targetSdk = context.getApplicationInfo().targetSdkVersion;
         final boolean targetPreHoneycomb = targetSdk < android.os.Build.VERSION_CODES.HONEYCOMB;
         final boolean targetPreIcs = targetSdk < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
+        final boolean targetPreL = targetSdk < android.os.Build.VERSION_CODES.L;
         final boolean targetHcNeedsOptions = context.getResources().getBoolean(
                 com.android.internal.R.bool.target_honeycomb_needs_options_menu);
         final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE);
@@ -3018,7 +3072,21 @@
         } else {
             clearFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);
         }
-        
+
+        // Non-floating windows on high end devices must put up decor beneath the system bars and
+        // therefore must know about visibility changes of those.
+        if (!mIsFloating && ActivityManager.isHighEndGfx()) {
+            if (!targetPreL && a.getBoolean(
+                    com.android.internal.R.styleable.Window_windowDrawsSystemBarBackgrounds,
+                    false)) {
+                setFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                        FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS & ~getForcedWindowFlags());
+            }
+            decor.setOnSystemUiVisibilityChangeListener(decor);
+        }
+        mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
+        mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
+
         if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
                 >= android.os.Build.VERSION_CODES.HONEYCOMB) {
             if (a.getBoolean(
@@ -3522,6 +3590,14 @@
         return (mLeftIconView = (ImageView)findViewById(com.android.internal.R.id.left_icon));
     }
 
+    @Override
+    protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
+        super.dispatchWindowAttributesChanged(attrs);
+        if (mDecor != null) {
+            mDecor.updateColorViews(null /* insets */);
+        }
+    }
+
     private ProgressBar getCircularProgressBar(boolean shouldInstallDecor) {
         if (mCircularProgressBar != null) {
             return mCircularProgressBar;
@@ -4166,4 +4242,22 @@
     void sendCloseSystemWindows(String reason) {
         PhoneWindowManager.sendCloseSystemWindows(getContext(), reason);
     }
+
+    @Override
+    public int getStatusBarColor() {
+        return 0;
+    }
+
+    @Override
+    public void setStatusBarColor(int color) {
+    }
+
+    @Override
+    public int getNavigationBarColor() {
+        return 0;
+    }
+
+    @Override
+    public void setNavigationBarColor(int color) {
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 4ee8103..8eed414 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -170,7 +170,8 @@
               View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
             | View.SYSTEM_UI_FLAG_FULLSCREEN
             | View.STATUS_BAR_TRANSLUCENT
-            | View.NAVIGATION_BAR_TRANSLUCENT;
+            | View.NAVIGATION_BAR_TRANSLUCENT
+            | View.SYSTEM_UI_TRANSPARENT;
 
     /**
      * Keyguard stuff
@@ -1368,6 +1369,13 @@
             // The status bar is the only window allowed to exhibit keyguard behavior.
             attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
         }
+
+        if (ActivityManager.isHighEndGfx()
+                && (attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
+            attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+        }
     }
     
     void readLidState() {
@@ -2708,7 +2716,8 @@
             // drive nav being hidden only by whether it is requested.
             final int sysui = mLastSystemUiFlags;
             boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
-            boolean navTranslucent = (sysui & View.NAVIGATION_BAR_TRANSLUCENT) != 0;
+            boolean navTranslucent = (sysui
+                    & (View.NAVIGATION_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0;
             boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
             boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
             boolean navAllowedHidden = immersive || immersiveSticky;
@@ -2834,7 +2843,8 @@
                 mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;
 
                 boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
-                boolean statusBarTranslucent = (sysui & View.STATUS_BAR_TRANSLUCENT) != 0;
+                boolean statusBarTranslucent = (sysui
+                        & (View.STATUS_BAR_TRANSLUCENT | View.SYSTEM_UI_TRANSPARENT)) != 0;
                 statusBarTranslucent &= areTranslucentBarsAllowed();
 
                 // If the status bar is hidden, we don't want to cause
@@ -3030,12 +3040,16 @@
             if (isAppWindow && !inheritTranslucentDecor && !topAtRest) {
                 if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
                         && (fl & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0
-                        && (fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) == 0) {
+                        && (fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) == 0
+                        && (fl & WindowManager.LayoutParams.
+                                FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
                     // Ensure policy decor includes status bar
                     dcf.top = mStableTop;
                 }
                 if ((fl & WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) == 0
-                        && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
+                        && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
+                        && (fl & WindowManager.LayoutParams.
+                                FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
                     // Ensure policy decor includes navigation bar
                     dcf.bottom = mStableBottom;
                     dcf.right = mStableRight;
@@ -5232,7 +5246,8 @@
         }
 
         if (!areTranslucentBarsAllowed()) {
-            vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT);
+            vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSLUCENT
+                    | View.SYSTEM_UI_TRANSPARENT);
         }
 
         // update status bar
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index e26747c..be20616 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -36,12 +36,14 @@
 import android.media.AudioService;
 import android.os.AsyncTask;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
@@ -49,6 +51,7 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.util.TimeUtils;
 import android.util.Xml;
 
@@ -56,6 +59,7 @@
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
+import com.google.android.util.AbstractMessageParser.MusicTrack;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -91,6 +95,10 @@
     final SparseArray<HashMap<String, Ops>> mUidOps
             = new SparseArray<HashMap<String, Ops>>();
 
+    private int mDeviceOwnerUid;
+    private final SparseIntArray mProfileOwnerUids = new SparseIntArray();
+    private final SparseArray<boolean[]> mOpRestrictions = new SparseArray<boolean[]>();
+
     public final static class Ops extends SparseArray<Op> {
         public final String packageName;
         public final int uid;
@@ -548,6 +556,9 @@
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
         synchronized (this) {
+            if (isOpRestricted(uid, code)) {
+                return AppOpsManager.MODE_IGNORED;
+            }
             Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false);
             if (op == null) {
                 return AppOpsManager.opToDefaultMode(code);
@@ -631,6 +642,9 @@
                 return AppOpsManager.MODE_ERRORED;
             }
             Op op = getOpLocked(ops, code, true);
+            if (isOpRestricted(uid, code)) {
+                return AppOpsManager.MODE_IGNORED;
+            }
             if (op.duration == -1) {
                 Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
                         + " code " + code + " time=" + op.time + " duration=" + op.duration);
@@ -665,6 +679,9 @@
                 return AppOpsManager.MODE_ERRORED;
             }
             Op op = getOpLocked(ops, code, true);
+            if (isOpRestricted(uid, code)) {
+                return AppOpsManager.MODE_IGNORED;
+            }
             final int switchCode = AppOpsManager.opToSwitch(code);
             final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
             if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
@@ -830,6 +847,23 @@
         return op;
     }
 
+    private boolean isOpRestricted(int uid, int code) {
+        int userHandle = UserHandle.getUserId(uid);
+        boolean[] opRestrictions = mOpRestrictions.get(userHandle);
+        if ((opRestrictions != null) && opRestrictions[code]) {
+            if (userHandle == UserHandle.USER_OWNER) {
+                if (uid != mDeviceOwnerUid) {
+                    return true;
+                }
+            } else {
+                if (uid != mProfileOwnerUids.get(userHandle, -1)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     void readState() {
         synchronized (mFile) {
             synchronized (this) {
@@ -1167,4 +1201,66 @@
         int mode;
         ArraySet<String> exceptionPackages = NO_EXCEPTIONS;
     }
+
+    @Override
+    public void setDeviceOwner(String packageName) throws RemoteException {
+        checkSystemUid("setDeviceOwner");
+        try {
+            mDeviceOwnerUid = mContext.getPackageManager().getPackageUid(packageName,
+                    UserHandle.USER_OWNER);
+        } catch (NameNotFoundException e) {
+            Log.e(TAG, "Could not find Device Owner UID");
+            mDeviceOwnerUid = -1;
+            throw new IllegalArgumentException("Could not find device owner package "
+                    + packageName);
+        }
+    }
+
+    @Override
+    public void setProfileOwner(String packageName, int userHandle) throws RemoteException {
+        checkSystemUid("setProfileOwner");
+        try {
+            int uid = mContext.getPackageManager().getPackageUid(packageName,
+                    userHandle);
+            mProfileOwnerUids.put(userHandle, uid);
+        } catch (NameNotFoundException e) {
+            Log.e(TAG, "Could not find Profile Owner UID");
+            mProfileOwnerUids.put(userHandle, -1);
+            throw new IllegalArgumentException("Could not find profile owner package "
+                    + packageName);
+        }
+    }
+
+    @Override
+    public void setUserRestrictions(Bundle restrictions, int userHandle) throws RemoteException {
+        checkSystemUid("setUserRestrictions");
+        boolean[] opRestrictions = mOpRestrictions.get(userHandle);
+        if (opRestrictions == null) {
+            opRestrictions = new boolean[AppOpsManager._NUM_OP];
+            mOpRestrictions.put(userHandle, opRestrictions);
+        }
+        for (int i = 0; i < opRestrictions.length; ++i) {
+            String restriction = AppOpsManager.opToRestriction(i);
+            if (restriction != null) {
+                opRestrictions[i] = restrictions.getBoolean(restriction, false);
+            } else {
+                opRestrictions[i] = false;
+            }
+        }
+    }
+
+    @Override
+    public void removeUser(int userHandle) throws RemoteException {
+        checkSystemUid("removeUser");
+        mOpRestrictions.remove(userHandle);
+        mProfileOwnerUids.removeAt(mProfileOwnerUids.indexOfKey(userHandle));
+    }
+
+    private void checkSystemUid(String function) {
+        int uid = Binder.getCallingUid();
+        if (uid != Process.SYSTEM_UID) {
+            throw new SecurityException(function + " must by called by the system");
+        }
+    }
+
 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0708e55..2d0f6d1 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3216,6 +3216,7 @@
             // tell the network currently servicing this that it's no longer interested
             NetworkAgentInfo affectedNetwork = mNetworkForRequestId.get(nri.request.requestId);
             if (affectedNetwork != null) {
+                mNetworkForRequestId.remove(nri.request.requestId);
                 affectedNetwork.networkRequests.remove(nri.request.requestId);
                 if (VDBG) {
                     log(" Removing from current network " + affectedNetwork.name() + ", leaving " +
@@ -5491,10 +5492,29 @@
             } catch (Exception e) {
                 loge("Exception in setDnsServersForNetwork: " + e);
             }
-            // TODO - setprop "net.dnsX"
+            NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId);
+            if (defaultNai != null && defaultNai.network.netId == netId) {
+                setDefaultDnsSystemProperties(dnses);
+            }
         }
     }
 
+    private void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
+        int last = 0;
+        for (InetAddress dns : dnses) {
+            ++last;
+            String key = "net.dns" + last;
+            String value = dns.getHostAddress();
+            SystemProperties.set(key, value);
+        }
+        for (int i = last + 1; i <= mNumDnsEntries; ++i) {
+            String key = "net.dns" + i;
+            SystemProperties.set(key, "");
+        }
+        mNumDnsEntries = last;
+    }
+
+
     private void updateCapabilities(NetworkAgentInfo networkAgent,
             NetworkCapabilities networkCapabilities) {
         // TODO - what else here?  Verify still satisfies everybody?
@@ -5610,6 +5630,11 @@
                     if (mDefaultRequest.requestId == nri.request.requestId) {
                         isNewDefault = true;
                         updateActiveDefaultNetwork(newNetwork);
+                        if (newNetwork.linkProperties != null) {
+                            setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnses());
+                        } else {
+                            setDefaultDnsSystemProperties(new ArrayList<InetAddress>());
+                        }
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index dd12a65..249422b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -27,6 +27,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Parcel;
+import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -40,6 +41,7 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.PowerProfile;
+import com.android.server.LocalServices;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -49,7 +51,8 @@
  * All information we are collecting about things that can happen that impact
  * battery life.
  */
-public final class BatteryStatsService extends IBatteryStats.Stub {
+public final class BatteryStatsService extends IBatteryStats.Stub
+        implements PowerManagerInternal.LowPowerModeListener {
     static final String TAG = "BatteryStatsService";
 
     static IBatteryStats sService;
@@ -58,6 +61,7 @@
     Context mContext;
     private boolean mBluetoothPendingStats;
     private BluetoothHeadset mBluetoothHeadset;
+    PowerManagerInternal mPowerManagerInternal;
 
     BatteryStatsService(String filename, Handler handler) {
         mStats = new BatteryStatsImpl(filename, handler);
@@ -70,6 +74,9 @@
         mStats.setRadioScanningTimeout(mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_radioScanningTimeout)
                 * 1000L);
+        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
+        mPowerManagerInternal.registerLowPowerModeObserver(this);
+        mStats.noteLowPowerMode(mPowerManagerInternal.getLowPowerModeEnabled());
         (new WakeupReasonThread()).start();
      }
     
@@ -88,7 +95,14 @@
         sService = asInterface(b);
         return sService;
     }
-    
+
+    @Override
+    public void onLowPowerModeChanged(boolean enabled) {
+        synchronized (mStats) {
+            mStats.noteLowPowerMode(enabled);
+        }
+    }
+
     /**
      * @return the current statistics object, which may be modified
      * to reflect events that affect battery usage.  You must lock the
@@ -154,11 +168,11 @@
         }
     }
 
-    public void noteStopWakelock(int uid, int pid, String name, int type) {
+    public void noteStopWakelock(int uid, int pid, String name, String historyName, int type) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteStopWakeLocked(uid, pid, name, type, SystemClock.elapsedRealtime(),
-                    SystemClock.uptimeMillis());
+            mStats.noteStopWakeLocked(uid, pid, name, historyName, type,
+                    SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
         }
     }
 
@@ -171,20 +185,21 @@
         }
     }
 
-    public void noteChangeWakelockFromSource(WorkSource ws, int pid, String name, int type,
-            WorkSource newWs, int newPid, String newName,
+    public void noteChangeWakelockFromSource(WorkSource ws, int pid, String name,
+            String historyName, int type, WorkSource newWs, int newPid, String newName,
             String newHistoryName, int newType, boolean newUnimportantForLogging) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, type,
+            mStats.noteChangeWakelockFromSourceLocked(ws, pid, name, historyName, type,
                     newWs, newPid, newName, newHistoryName, newType, newUnimportantForLogging);
         }
     }
 
-    public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, int type) {
+    public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, String historyName,
+            int type) {
         enforceCallingPermission();
         synchronized (mStats) {
-            mStats.noteStopWakeFromSourceLocked(ws, pid, name, type);
+            mStats.noteStopWakeFromSourceLocked(ws, pid, name, historyName, type);
         }
     }
 
@@ -608,10 +623,35 @@
         pw.println("  --charged: only output data since last charged.");
         pw.println("  --reset: reset the stats, clearing all current data.");
         pw.println("  --write: force write current collected stats to disk.");
+        pw.println("  --enable: enable an option: full-wake-history, no-auto-reset.");
+        pw.println("  --disable: disable an option: full-wake-history, no-auto-reset.");
         pw.println("  -h: print this help text.");
         pw.println("  <package.name>: optional name of package to filter output by.");
     }
 
+    private int doEnableOrDisable(PrintWriter pw, int i, String[] args, boolean enable) {
+        i++;
+        if (i >= args.length) {
+            pw.println("Missing option argument for " + (enable ? "--enable" : "--disable"));
+            dumpHelp(pw);
+            return -1;
+        }
+        if ("full-wake-history".equals(args[i])) {
+            synchronized (mStats) {
+                mStats.setRecordAllWakeLocksLocked(enable);
+            }
+        } else if ("no-auto-reset".equals(args[i])) {
+            synchronized (mStats) {
+                mStats.setNoAutoReset(enable);
+            }
+        } else {
+            pw.println("Unknown enable/disable option: " + args[i]);
+            dumpHelp(pw);
+            return -1;
+        }
+        return i;
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -662,6 +702,20 @@
                         pw.println("Battery stats written.");
                         noOutput = true;
                     }
+                } else if ("--enable".equals(arg)) {
+                    i = doEnableOrDisable(pw, i, args, true);
+                    if (i < 0) {
+                        return;
+                    }
+                    pw.println("Enabled: " + args[i]);
+                    return;
+                } else if ("--disable".equals(arg)) {
+                    i = doEnableOrDisable(pw, i, args, false);
+                    if (i < 0) {
+                        return;
+                    }
+                    pw.println("Disabled: " + args[i]);
+                    return;
                 } else if ("-h".equals(arg)) {
                     dumpHelp(pw);
                     return;
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 3884ab0..096ab66 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -74,6 +74,14 @@
         mIsStarted = false;
         mIsRunning = false;
         mLP = new LinkProperties();
+
+        // If this is a runtime restart, it's possible that clatd is already
+        // running, but we don't know about it. If so, stop it.
+        try {
+            if (mNMService.isClatdStarted()) {
+                mNMService.stopClatd();
+            }
+        } catch(RemoteException e) {}  // Well, we tried.
     }
 
     /**
@@ -198,13 +206,13 @@
                 NetworkUtils.resetConnections(
                     CLAT_INTERFACE_NAME,
                     NetworkUtils.RESET_IPV4_ADDRESSES);
+                mBaseLP.removeStackedLink(mLP);
+                updateConnectivityService();
             }
             Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME +
                    " removed, mIsRunning = " + mIsRunning + " -> false");
             mIsRunning = false;
-            mBaseLP.removeStackedLink(mLP);
             mLP.clear();
-            updateConnectivityService();
             Slog.i(TAG, "mLP = " + mLP);
         }
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index fc6183c..6d2b83b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -58,14 +58,14 @@
     }
 
     /**
-     * Build &lt;Get Osd Name&gt; command.
+     * Build &lt;Give Osd Name&gt; command.
      *
      * @param src source address of command
      * @param dest destination address of command
      * @return newly created {@link HdmiCecMessage}
      */
-    static HdmiCecMessage buildGetOsdNameCommand(int src, int dest) {
-        return buildCommand(src, dest, HdmiCec.MESSAGE_GET_OSD_NAME);
+    static HdmiCecMessage buildGiveOsdNameCommand(int src, int dest) {
+        return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_OSD_NAME);
     }
 
     /**
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index c122645..ed48c12 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -127,8 +127,8 @@
             case HdmiCec.MESSAGE_GET_MENU_LANGUAGE:
                 handleGetMenuLanguage(message);
                 return true;
-            case HdmiCec.MESSAGE_GET_OSD_NAME:
-                handleGetOsdName(message);
+            case HdmiCec.MESSAGE_GIVE_OSD_NAME:
+                handleGiveOsdName(message);
                 return true;
             case HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS:
                 handleGivePhysicalAddress(message);
@@ -170,7 +170,7 @@
         sendCecCommand(cecMessage);
     }
 
-    private void handleGetOsdName(HdmiCecMessage message) {
+    private void handleGiveOsdName(HdmiCecMessage message) {
         // TODO: read device name from settings or property.
         String name = HdmiCec.getDefaultDeviceName(message.getDestination());
         HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand(
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index 98da280..e0bc718 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -71,7 +71,7 @@
     @Override
     public boolean start() {
         sendCommand(
-                HdmiCecMessageBuilder.buildGetOsdNameCommand(mSourceAddress,
+                HdmiCecMessageBuilder.buildGiveOsdNameCommand(mSourceAddress,
                         mDeviceLogicalAddress));
         mState = STATE_WAITING_FOR_SET_OSD_NAME;
         addTimer(mState, TIMEOUT_MS);
diff --git a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
index c4e2058..1c5cacd 100644
--- a/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRouteProviderProxy.java
@@ -58,12 +58,16 @@
     private final int mUserId;
     // Interfaces declared in the manifest
     private final ArrayList<String> mInterfaces = new ArrayList<String>();
-    private final ArrayList<RouteConnectionRecord> mConnections = new ArrayList<RouteConnectionRecord>();
+    private final ArrayList<RouteConnectionRecord> mConnections
+            = new ArrayList<RouteConnectionRecord>();
+    // The sessions that have a route from this provider selected
+    private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
     private final Handler mHandler = new Handler();
 
     private Intent mBindIntent;
     private IRouteProvider mBinder;
     private boolean mRunning;
+    private boolean mPaused;
     private boolean mInterested;
     private boolean mBound;
     private int mRetryCount;
@@ -83,6 +87,12 @@
         mBindIntent.setComponent(mComponentName);
     }
 
+    public void destroy() {
+        stop();
+        mSessions.clear();
+        updateBinding();
+    }
+
     /**
      * Send any cleanup messages and unbind from the media route provider
      */
@@ -236,6 +246,19 @@
         return mId;
     }
 
+    public void addSession(MediaSessionRecord session) {
+        mSessions.add(session);
+    }
+
+    public void removeSession(MediaSessionRecord session) {
+        mSessions.remove(session);
+        updateBinding();
+    }
+
+    public int getSessionCount() {
+        return mSessions.size();
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         pw.println(prefix + mId + " " + this);
         String indent = prefix + "  ";
@@ -257,8 +280,10 @@
         }
     }
 
+    // We want to bind as long as we're interested in this provider or there are
+    // sessions connected to it.
     private boolean shouldBind() {
-        return mRunning && mInterested;
+        return (mRunning && mInterested) || (!mSessions.isEmpty());
     }
 
     private void bind() {
diff --git a/services/core/java/com/android/server/media/MediaRouteProviderWatcher.java b/services/core/java/com/android/server/media/MediaRouteProviderWatcher.java
index cf1d95ab..734eab9 100644
--- a/services/core/java/com/android/server/media/MediaRouteProviderWatcher.java
+++ b/services/core/java/com/android/server/media/MediaRouteProviderWatcher.java
@@ -90,6 +90,8 @@
         }
     }
 
+    // Stop discovering providers and routes. Providers that still have an
+    // active session connected to them will not unbind.
     public void stop() {
         if (mRunning) {
             mRunning = false;
@@ -97,13 +99,21 @@
             mContext.unregisterReceiver(mScanPackagesReceiver);
             mHandler.removeCallbacks(mScanPackagesRunnable);
 
-            // Stop all providers.
+            // Stop all inactive providers.
             for (int i = mProviders.size() - 1; i >= 0; i--) {
                 mProviders.get(i).stop();
             }
         }
     }
 
+    // Clean up the providers forcibly unbinding if necessary
+    public void destroy() {
+        for (int i = mProviders.size() - 1; i >= 0; i--) {
+            mProviders.get(i).destroy();
+            mProviders.remove(i);
+        }
+    }
+
     public ArrayList<MediaRouteProviderProxy> getProviders() {
         return mProviders;
     }
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 41ab626..9677577 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -113,6 +113,7 @@
     // End TransportPerformer fields
 
     private boolean mIsActive = false;
+    private boolean mDestroyed = false;
 
     public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
             ISessionCallback cb, String tag, MediaSessionService service, Handler handler) {
@@ -220,10 +221,7 @@
     public void selectRoute(RouteInfo route) {
         synchronized (mLock) {
             if (route != mRoute) {
-                if (mConnection != null) {
-                    mConnection.disconnect();
-                    mConnection = null;
-                }
+                disconnect(Session.DISCONNECT_REASON_ROUTE_CHANGED);
             }
             mRoute = route;
         }
@@ -261,14 +259,19 @@
     public boolean setRouteConnected(RouteInfo route, RouteOptions request,
             RouteConnectionRecord connection) {
         synchronized (mLock) {
+            if (mDestroyed) {
+                Log.i(TAG, "setRouteConnected: session has been destroyed");
+                connection.disconnect();
+                return false;
+            }
             if (mRoute == null || !TextUtils.equals(route.getId(), mRoute.getId())) {
                 Log.w(TAG, "setRouteConnected: connected route is stale");
-                // TODO figure out disconnection path
+                connection.disconnect();
                 return false;
             }
             if (request != mRequest) {
                 Log.w(TAG, "setRouteConnected: connection request is stale");
-                // TODO figure out disconnection path
+                connection.disconnect();
                 return false;
             }
             mConnection = connection;
@@ -284,7 +287,7 @@
      * @return True if the session is active, false otherwise.
      */
     public boolean isActive() {
-        return mIsActive;
+        return mIsActive && !mDestroyed;
     }
 
     /**
@@ -307,6 +310,30 @@
         return false;
     }
 
+    /**
+     * @return True if this session is currently connected to a route.
+     */
+    public boolean isConnected() {
+        return mConnection != null;
+    }
+
+    public void disconnect(int reason) {
+        synchronized (mLock) {
+            if (!mDestroyed) {
+                disconnectLocked(reason);
+            }
+        }
+    }
+
+    private void disconnectLocked(int reason) {
+        if (mConnection != null) {
+            mConnection.setListener(null);
+            mConnection.disconnect();
+            mConnection = null;
+            pushDisconnected(reason);
+        }
+    }
+
     public boolean isTransportControlEnabled() {
         return hasFlag(Session.FLAG_HANDLES_TRANSPORT_CONTROLS);
     }
@@ -316,6 +343,28 @@
         mService.sessionDied(this);
     }
 
+    /**
+     * Finish cleaning up this session, including disconnecting if connected and
+     * removing the death observer from the callback binder.
+     */
+    public void onDestroy() {
+        synchronized (mLock) {
+            if (mDestroyed) {
+                return;
+            }
+            if (isConnected()) {
+                disconnectLocked(Session.DISCONNECT_REASON_SESSION_DESTROYED);
+            }
+            mRoute = null;
+            mRequest = null;
+            mDestroyed = true;
+        }
+    }
+
+    public ISessionCallback getCallback() {
+        return mSessionCb.mCb;
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         pw.println(prefix + mTag + " " + this);
 
@@ -323,7 +372,7 @@
         pw.println(indent + "ownerPid=" + mOwnerPid + ", ownerUid=" + mOwnerUid
                 + ", userId=" + mUserId);
         pw.println(indent + "info=" + mSessionInfo.toString());
-        pw.println(indent + "published=" + mIsActive);
+        pw.println(indent + "active=" + mIsActive);
         pw.println(indent + "flags=" + mFlags);
         pw.println(indent + "rating type=" + mRatingType);
         pw.println(indent + "controllers: " + mControllerCallbacks.size());
@@ -356,12 +405,17 @@
         return "size=" + fields + ", title=" + title;
     }
 
-    private void onDestroy() {
-        mService.destroySession(this);
+    private void pushDisconnected(int reason) {
+        synchronized (mLock) {
+            mSessionCb.sendRouteDisconnected(reason);
+        }
     }
 
     private void pushPlaybackStateUpdate() {
         synchronized (mLock) {
+            if (mDestroyed) {
+                return;
+            }
             for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
                 ISessionControllerCallback cb = mControllerCallbacks.get(i);
                 try {
@@ -376,6 +430,9 @@
 
     private void pushMetadataUpdate() {
         synchronized (mLock) {
+            if (mDestroyed) {
+                return;
+            }
             for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
                 ISessionControllerCallback cb = mControllerCallbacks.get(i);
                 try {
@@ -390,6 +447,9 @@
 
     private void pushRouteUpdate() {
         synchronized (mLock) {
+            if (mDestroyed) {
+                return;
+            }
             for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
                 ISessionControllerCallback cb = mControllerCallbacks.get(i);
                 try {
@@ -404,6 +464,9 @@
 
     private void pushEvent(String event, Bundle data) {
         synchronized (mLock) {
+            if (mDestroyed) {
+                return;
+            }
             for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) {
                 ISessionControllerCallback cb = mControllerCallbacks.get(i);
                 try {
@@ -417,6 +480,9 @@
 
     private void pushRouteCommand(RouteCommand command, ResultReceiver cb) {
         synchronized (mLock) {
+            if (mDestroyed) {
+                return;
+            }
             if (mRoute == null || !TextUtils.equals(command.getRouteInfo(), mRoute.getId())) {
                 if (cb != null) {
                     cb.send(RouteInterface.RESULT_ROUTE_IS_STALE, null);
@@ -470,14 +536,14 @@
 
         @Override
         public void disconnect() {
-            // TODO
+            MediaSessionRecord.this.disconnect(Session.DISCONNECT_REASON_PROVIDER_DISCONNECTED);
         }
     };
 
     private final class SessionStub extends ISession.Stub {
         @Override
         public void destroy() {
-            onDestroy();
+            mService.destroySession(MediaSessionRecord.this);
         }
 
         @Override
@@ -554,6 +620,14 @@
         }
 
         @Override
+        public void disconnectFromRoute(RouteInfo route) {
+            if (route != null && mRoute != null
+                    && TextUtils.equals(route.getId(), mRoute.getId())) {
+                disconnect(Session.DISCONNECT_REASON_SESSION_DISCONNECTED);
+            }
+        }
+
+        @Override
         public void setRouteOptions(List<RouteOptions> options) throws RemoteException {
             mRequests.clear();
             for (int i = options.size() - 1; i >= 0; i--) {
@@ -621,6 +695,14 @@
             }
         }
 
+        public void sendRouteDisconnected(int reason) {
+            try {
+                mCb.onRouteDisconnected(mRoute, reason);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Remote failure in sendRouteDisconnected");
+            }
+        }
+
         public void play() {
             try {
                 mCb.onPlay();
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 008f9be..78f3b5f 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -24,20 +24,19 @@
 import android.media.routeprovider.RouteRequest;
 import android.media.session.ISession;
 import android.media.session.ISessionCallback;
-import android.media.session.ISessionController;
 import android.media.session.ISessionManager;
-import android.media.session.PlaybackState;
 import android.media.session.RouteInfo;
 import android.media.session.RouteOptions;
+import android.media.session.Session;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.SparseArray;
 
 import com.android.server.SystemService;
 import com.android.server.Watchdog;
@@ -56,16 +55,18 @@
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final SessionManagerImpl mSessionManagerImpl;
-    private final MediaRouteProviderWatcher mRouteProviderWatcher;
+    // private final MediaRouteProviderWatcher mRouteProviderWatcher;
     private final MediaSessionStack mPriorityStack;
 
-    private final ArrayList<MediaSessionRecord> mRecords = new ArrayList<MediaSessionRecord>();
-    private final ArrayList<MediaRouteProviderProxy> mProviders
-            = new ArrayList<MediaRouteProviderProxy>();
+    private final ArrayList<MediaSessionRecord> mAllSessions = new ArrayList<MediaSessionRecord>();
+    private final SparseArray<UserRecord> mUserRecords = new SparseArray<UserRecord>();
+    // private final ArrayList<MediaRouteProviderProxy> mProviders
+    // = new ArrayList<MediaRouteProviderProxy>();
     private final Object mLock = new Object();
     private final Handler mHandler = new Handler();
 
     private MediaSessionRecord mPrioritySession;
+    private int mCurrentUserId = -1;
 
     // Used to keep track of the current request to show routes for a specific
     // session so we drop late callbacks properly.
@@ -77,16 +78,14 @@
     public MediaSessionService(Context context) {
         super(context);
         mSessionManagerImpl = new SessionManagerImpl();
-        mRouteProviderWatcher = new MediaRouteProviderWatcher(context, mProviderWatcherCallback,
-                mHandler, context.getUserId());
         mPriorityStack = new MediaSessionStack();
     }
 
     @Override
     public void onStart() {
         publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl);
-        mRouteProviderWatcher.start();
         Watchdog.getInstance().addMonitor(this);
+        updateUser();
     }
 
     /**
@@ -98,16 +97,28 @@
     public void showRoutePickerForSession(MediaSessionRecord record) {
         // TODO for now just toggle the route to test (we will only have one
         // match for now)
-        if (record.getRoute() != null) {
-            // For now send null to mean the local route
-            record.selectRoute(null);
-            return;
-        }
-        mShowRoutesRequestId++;
-        ArrayList<MediaRouteProviderProxy> providers = mRouteProviderWatcher.getProviders();
-        for (int i = providers.size() - 1; i >= 0; i--) {
-            MediaRouteProviderProxy provider = providers.get(i);
-            provider.getRoutes(record, mShowRoutesRequestId);
+        synchronized (mLock) {
+            if (!mAllSessions.contains(record)) {
+                Log.d(TAG, "Unknown session tried to show route picker. Ignoring.");
+                return;
+            }
+            RouteInfo current = record.getRoute();
+            UserRecord user = mUserRecords.get(record.getUserId());
+            if (current != null) {
+                // For now send null to mean the local route
+                MediaRouteProviderProxy proxy = user.getProviderLocked(current.getProvider());
+                if (proxy != null) {
+                    proxy.removeSession(record);
+                }
+                record.selectRoute(null);
+                return;
+            }
+            ArrayList<MediaRouteProviderProxy> providers = user.getProvidersLocked();
+            mShowRoutesRequestId++;
+            for (int i = providers.size() - 1; i >= 0; i--) {
+                MediaRouteProviderProxy provider = providers.get(i);
+                provider.getRoutes(record, mShowRoutesRequestId);
+            }
         }
     }
 
@@ -121,19 +132,31 @@
     public void connectToRoute(MediaSessionRecord session, RouteInfo route,
             RouteOptions options) {
         synchronized (mLock) {
-            MediaRouteProviderProxy proxy = getProviderLocked(route.getProvider());
+            if (!mAllSessions.contains(session)) {
+                Log.d(TAG, "Unknown session attempting to connect to route. Ignoring");
+                return;
+            }
+            UserRecord user = mUserRecords.get(session.getUserId());
+            if (user == null) {
+                Log.wtf(TAG, "connectToRoute: User " + session.getUserId() + " does not exist.");
+                return;
+            }
+            MediaRouteProviderProxy proxy = user.getProviderLocked(route.getProvider());
             if (proxy == null) {
                 Log.w(TAG, "Provider for route " + route.getName() + " does not exist.");
                 return;
             }
             RouteRequest request = new RouteRequest(session.getSessionInfo(), options, true);
-            // TODO make connect an async call to a ThreadPoolExecutor
             proxy.connectToRoute(session, route, request);
         }
     }
 
     public void updateSession(MediaSessionRecord record) {
         synchronized (mLock) {
+            if (!mAllSessions.contains(record)) {
+                Log.d(TAG, "Unknown session updated. Ignoring.");
+                return;
+            }
             mPriorityStack.onSessionStateChange(record);
             if (record.isSystemPriority()) {
                 if (record.isActive()) {
@@ -152,17 +175,48 @@
 
     public void onSessionPlaystateChange(MediaSessionRecord record, int oldState, int newState) {
         synchronized (mLock) {
+            if (!mAllSessions.contains(record)) {
+                Log.d(TAG, "Unknown session changed playback state. Ignoring.");
+                return;
+            }
             mPriorityStack.onPlaystateChange(record, oldState, newState);
         }
     }
 
     @Override
+    public void onStartUser(int userHandle) {
+        updateUser();
+    }
+
+    @Override
+    public void onSwitchUser(int userHandle) {
+        updateUser();
+    }
+
+    @Override
+    public void onStopUser(int userHandle) {
+        synchronized (mLock) {
+            UserRecord user = mUserRecords.get(userHandle);
+            if (user != null) {
+                destroyUserLocked(user);
+            }
+        }
+    }
+
+    @Override
     public void monitor() {
         synchronized (mLock) {
             // Check for deadlock
         }
     }
 
+    protected void enforcePhoneStatePermission(int pid, int uid) {
+        if (getContext().checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Must hold the MODIFY_PHONE_STATE permission.");
+        }
+    }
+
     void sessionDied(MediaSessionRecord session) {
         synchronized (mLock) {
             destroySessionLocked(session);
@@ -175,12 +229,63 @@
         }
     }
 
+    private void updateUser() {
+        synchronized (mLock) {
+            int userId = ActivityManager.getCurrentUser();
+            if (mCurrentUserId != userId) {
+                final int oldUserId = mCurrentUserId;
+                mCurrentUserId = userId; // do this first
+
+                UserRecord oldUser = mUserRecords.get(oldUserId);
+                if (oldUser != null) {
+                    oldUser.stopLocked();
+                }
+
+                UserRecord newUser = getOrCreateUser(userId);
+                newUser.startLocked();
+            }
+        }
+    }
+
+    /**
+     * Stop the user and unbind from everything.
+     *
+     * @param user The user to dispose of
+     */
+    private void destroyUserLocked(UserRecord user) {
+        user.stopLocked();
+        user.destroyLocked();
+        mUserRecords.remove(user.mUserId);
+    }
+
+    /*
+     * When a session is removed several things need to happen.
+     * 1. We need to remove it from the relevant user.
+     * 2. We need to remove it from the priority stack.
+     * 3. We need to remove it from all sessions.
+     * 4. If this is the system priority session we need to clear it.
+     * 5. We need to unlink to death from the cb binder
+     * 6. We need to tell the session to do any final cleanup (onDestroy)
+     */
     private void destroySessionLocked(MediaSessionRecord session) {
-        mRecords.remove(session);
+        int userId = session.getUserId();
+        UserRecord user = mUserRecords.get(userId);
+        if (user != null) {
+            user.removeSessionLocked(session);
+        }
+
         mPriorityStack.removeSession(session);
+        mAllSessions.remove(session);
         if (session == mPrioritySession) {
             mPrioritySession = null;
         }
+
+        try {
+            session.getCallback().asBinder().unlinkToDeath(session, 0);
+        } catch (Exception e) {
+            // ignore exceptions while destroying a session.
+        }
+        session.onDestroy();
     }
 
     private void enforcePackageName(String packageName, int uid) {
@@ -197,13 +302,6 @@
         throw new IllegalArgumentException("packageName is not owned by the calling process");
     }
 
-    protected void enforcePhoneStatePermission(int pid, int uid) {
-        if (getContext().checkPermission(android.Manifest.permission.MODIFY_PHONE_STATE, pid, uid)
-                != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Must hold the MODIFY_PHONE_STATE permission.");
-        }
-    }
-
     /**
      * Checks a caller's authorization to register an IRemoteControlDisplay.
      * Authorization is granted if one of the following is true:
@@ -271,14 +369,22 @@
     }
 
     private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
-            String callerPackageName, ISessionCallback cb, String tag) {
+            String callerPackageName, ISessionCallback cb, String tag) throws RemoteException {
         synchronized (mLock) {
             return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag);
         }
     }
 
+    /*
+     * When a session is created the following things need to happen.
+     * 1. It's callback binder needs a link to death
+     * 2. It needs to be added to all sessions.
+     * 3. It needs to be added to the priority stack.
+     * 4. It needs to be added to the relevant user record.
+     */
     private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
             String callerPackageName, ISessionCallback cb, String tag) {
+
         final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
                 callerPackageName, cb, tag, this, mHandler);
         try {
@@ -286,17 +392,31 @@
         } catch (RemoteException e) {
             throw new RuntimeException("Media Session owner died prematurely.", e);
         }
-        mRecords.add(session);
+
+        mAllSessions.add(session);
         mPriorityStack.addSession(session);
+
+        UserRecord user = getOrCreateUser(userId);
+        user.addSessionLocked(session);
+
         if (DEBUG) {
             Log.d(TAG, "Created session for package " + callerPackageName + " with tag " + tag);
         }
         return session;
     }
 
+    private UserRecord getOrCreateUser(int userId) {
+        UserRecord user = mUserRecords.get(userId);
+        if (user == null) {
+            user = new UserRecord(getContext(), userId);
+            mUserRecords.put(userId, user);
+        }
+        return user;
+    }
+
     private int findIndexOfSessionForIdLocked(String sessionId) {
-        for (int i = mRecords.size() - 1; i >= 0; i--) {
-            MediaSessionRecord session = mRecords.get(i);
+        for (int i = mAllSessions.size() - 1; i >= 0; i--) {
+            MediaSessionRecord session = mAllSessions.get(i);
             if (TextUtils.equals(session.getSessionInfo().getId(), sessionId)) {
                 return i;
             }
@@ -304,42 +424,11 @@
         return -1;
     }
 
-    private MediaRouteProviderProxy getProviderLocked(String providerId) {
-        for (int i = mProviders.size() - 1; i >= 0; i--) {
-            MediaRouteProviderProxy provider = mProviders.get(i);
-            if (TextUtils.equals(providerId, provider.getId())) {
-                return provider;
-            }
-        }
-        return null;
-    }
-
     private boolean isSessionDiscoverable(MediaSessionRecord record) {
-        // TODO probably want to check more than if it's published.
+        // TODO probably want to check more than if it's active.
         return record.isActive();
     }
 
-    private MediaRouteProviderWatcher.Callback mProviderWatcherCallback
-            = new MediaRouteProviderWatcher.Callback() {
-        @Override
-        public void removeProvider(MediaRouteProviderProxy provider) {
-            synchronized (mLock) {
-                mProviders.remove(provider);
-                provider.setRoutesListener(null);
-                provider.setInterested(false);
-            }
-        }
-
-        @Override
-        public void addProvider(MediaRouteProviderProxy provider) {
-            synchronized (mLock) {
-                mProviders.add(provider);
-                provider.setRoutesListener(mRoutesCallback);
-                provider.setInterested(true);
-            }
-        }
-    };
-
     private MediaRouteProviderProxy.RoutesListener mRoutesCallback
             = new MediaRouteProviderProxy.RoutesListener() {
         @Override
@@ -350,8 +439,12 @@
             synchronized (mLock) {
                 int index = findIndexOfSessionForIdLocked(sessionId);
                 if (index != -1 && routes != null && routes.size() > 0) {
-                    MediaSessionRecord record = mRecords.get(index);
-                    record.selectRoute(routes.get(0));
+                    MediaSessionRecord record = mAllSessions.get(index);
+                    RouteInfo route = routes.get(0);
+                    record.selectRoute(route);
+                    UserRecord user = mUserRecords.get(record.getUserId());
+                    MediaRouteProviderProxy provider = user.getProviderLocked(route.getProvider());
+                    provider.addSession(record);
                 }
             }
         }
@@ -362,13 +455,135 @@
             synchronized (mLock) {
                 int index = findIndexOfSessionForIdLocked(sessionId);
                 if (index != -1) {
-                    MediaSessionRecord session = mRecords.get(index);
+                    MediaSessionRecord session = mAllSessions.get(index);
                     session.setRouteConnected(route, options.getConnectionOptions(), connection);
                 }
             }
         }
     };
 
+    /**
+     * Information about a particular user. The contents of this object is
+     * guarded by mLock.
+     */
+    final class UserRecord {
+        private final int mUserId;
+        private final MediaRouteProviderWatcher mRouteProviderWatcher;
+        private final ArrayList<MediaRouteProviderProxy> mProviders
+                = new ArrayList<MediaRouteProviderProxy>();
+        private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
+
+        public UserRecord(Context context, int userId) {
+            mUserId = userId;
+            mRouteProviderWatcher = new MediaRouteProviderWatcher(context,
+                    mProviderWatcherCallback, mHandler, userId);
+        }
+
+        public void startLocked() {
+            mRouteProviderWatcher.start();
+        }
+
+        public void stopLocked() {
+            mRouteProviderWatcher.stop();
+            updateInterestLocked();
+        }
+
+        public void destroyLocked() {
+            for (int i = mSessions.size() - 1; i >= 0; i--) {
+                MediaSessionRecord session = mSessions.get(i);
+                MediaSessionService.this.destroySessionLocked(session);
+                if (session.isConnected()) {
+                    session.disconnect(Session.DISCONNECT_REASON_USER_STOPPING);
+                }
+            }
+        }
+
+        public ArrayList<MediaRouteProviderProxy> getProvidersLocked() {
+            return mProviders;
+        }
+
+        public ArrayList<MediaSessionRecord> getSessionsLocked() {
+            return mSessions;
+        }
+
+        public void addSessionLocked(MediaSessionRecord session) {
+            mSessions.add(session);
+            updateInterestLocked();
+        }
+
+        public void removeSessionLocked(MediaSessionRecord session) {
+            mSessions.remove(session);
+            RouteInfo route = session.getRoute();
+            if (route != null) {
+                MediaRouteProviderProxy provider = getProviderLocked(route.getProvider());
+                if (provider != null) {
+                    provider.removeSession(session);
+                }
+            }
+            updateInterestLocked();
+        }
+
+        public void dumpLocked(PrintWriter pw, String prefix) {
+            pw.println(prefix + "Record for user " + mUserId);
+            String indent = prefix + "  ";
+            int size = mProviders.size();
+            pw.println(indent + size + " Providers:");
+            for (int i = 0; i < size; i++) {
+                mProviders.get(i).dump(pw, indent);
+            }
+            pw.println();
+            size = mSessions.size();
+            pw.println(indent + size + " Sessions:");
+            for (int i = 0; i < size; i++) {
+                // Just print the session info, the full session dump will
+                // already be in the list of all sessions.
+                pw.println(indent + mSessions.get(i).getSessionInfo());
+            }
+        }
+
+        public void updateInterestLocked() {
+            // TODO go through the sessions and build up the set of interfaces
+            // we're interested in. Update the provider watcher.
+            // For now, just express interest in all providers for the current
+            // user
+            boolean interested = mUserId == mCurrentUserId;
+            for (int i = mProviders.size() - 1; i >= 0; i--) {
+                mProviders.get(i).setInterested(interested);
+            }
+        }
+
+        private MediaRouteProviderProxy getProviderLocked(String providerId) {
+            for (int i = mProviders.size() - 1; i >= 0; i--) {
+                MediaRouteProviderProxy provider = mProviders.get(i);
+                if (TextUtils.equals(providerId, provider.getId())) {
+                    return provider;
+                }
+            }
+            return null;
+        }
+
+        private MediaRouteProviderWatcher.Callback mProviderWatcherCallback
+                = new MediaRouteProviderWatcher.Callback() {
+            @Override
+            public void removeProvider(MediaRouteProviderProxy provider) {
+                synchronized (mLock) {
+                    mProviders.remove(provider);
+                    provider.setRoutesListener(null);
+                    provider.setInterested(false);
+                }
+            }
+
+            @Override
+            public void addProvider(MediaRouteProviderProxy provider) {
+                synchronized (mLock) {
+                    mProviders.add(provider);
+                    provider.setRoutesListener(mRoutesCallback);
+                    provider.setInterested(true);
+                }
+            }
+        };
+    }
+
     class SessionManagerImpl extends ISessionManager.Stub {
         // TODO add createSessionAsUser, pass user-id to
         // ActivityManagerNative.handleIncomingUser and stash result for use
@@ -447,19 +662,19 @@
                 if (mPrioritySession != null) {
                     mPrioritySession.dump(pw, "");
                 }
-                int count = mRecords.size();
+                int count = mAllSessions.size();
                 pw.println(count + " Sessions:");
                 for (int i = 0; i < count; i++) {
-                    mRecords.get(i).dump(pw, "");
+                    mAllSessions.get(i).dump(pw, "");
                     pw.println();
                 }
                 mPriorityStack.dump(pw, "");
 
-                pw.println("Providers:");
-                count = mProviders.size();
+                pw.println("User Records:");
+                count = mUserRecords.size();
                 for (int i = 0; i < count; i++) {
-                    MediaRouteProviderProxy provider = mProviders.get(i);
-                    provider.dump(pw, "");
+                    UserRecord user = mUserRecords.get(i);
+                    user.dumpLocked(pw, "");
                 }
             }
         }
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 1e1818d..f89b14a 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -19,7 +19,6 @@
 import android.media.session.PlaybackState;
 import android.media.session.Session;
 import android.os.UserHandle;
-import android.text.TextUtils;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -49,6 +48,8 @@
 
     private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
 
+    private MediaSessionRecord mGlobalPrioritySession;
+
     private MediaSessionRecord mCachedButtonReceiver;
     private MediaSessionRecord mCachedDefault;
     private ArrayList<MediaSessionRecord> mCachedActiveList;
@@ -61,6 +62,9 @@
      */
     public void addSession(MediaSessionRecord record) {
         mSessions.add(record);
+        if ((record.getFlags() & Session.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
+            mGlobalPrioritySession = record;
+        }
         clearCache();
     }
 
@@ -71,6 +75,9 @@
      */
     public void removeSession(MediaSessionRecord record) {
         mSessions.remove(record);
+        if (record == mGlobalPrioritySession) {
+            mGlobalPrioritySession = null;
+        }
         clearCache();
     }
 
@@ -156,6 +163,9 @@
      * @return The default media button session or null.
      */
     public MediaSessionRecord getDefaultMediaButtonSession(int userId) {
+        if (mGlobalPrioritySession != null && mGlobalPrioritySession.isActive()) {
+            return mGlobalPrioritySession;
+        }
         if (mCachedButtonReceiver != null) {
             return mCachedButtonReceiver;
         }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 60212bf..131d05b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -40,6 +40,7 @@
 import android.os.IUserManager;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.AtomicFile;
@@ -50,6 +51,7 @@
 import android.util.TimeUtils;
 import android.util.Xml;
 
+import com.android.internal.app.IAppOpsService;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
@@ -162,6 +164,8 @@
     private int mNextSerialNumber;
     private int mUserVersion = 0;
 
+    private IAppOpsService mAppOpsService;
+
     private static UserManagerService sInstance;
 
     public static UserManagerService getInstance() {
@@ -236,6 +240,15 @@
     void systemReady() {
         mUserPackageMonitor.register(mContext, null, UserHandle.ALL, false);
         userForeground(UserHandle.USER_OWNER);
+        mAppOpsService = IAppOpsService.Stub.asInterface(
+                ServiceManager.getService(Context.APP_OPS_SERVICE));
+        for (int i = 0; i < mUserIds.length; ++i) {
+            try {
+                mAppOpsService.setUserRestrictions(mUserRestrictions.get(mUserIds[i]), mUserIds[i]);
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
+            }
+        }
     }
 
     @Override
@@ -482,6 +495,14 @@
         synchronized (mPackagesLock) {
             mUserRestrictions.get(userId).clear();
             mUserRestrictions.get(userId).putAll(restrictions);
+            long token = Binder.clearCallingIdentity();
+            try {
+                mAppOpsService.setUserRestrictions(mUserRestrictions.get(userId), userId);
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
             writeUserLocked(mUsers.get(userId));
         }
     }
@@ -1116,6 +1137,11 @@
                 return false;
             }
             mRemovingUserIds.put(userHandle, true);
+            try {
+                mAppOpsService.removeUser(userHandle);
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, "Unable to notify AppOpsService of removing user", e);
+            }
             // Set this to a partially created user, so that the user will be purged
             // on next startup, in case the runtime stops now before stopping and
             // removing the user completely.
@@ -1125,6 +1151,14 @@
             user.flags |= UserInfo.FLAG_DISABLED;
             writeUserLocked(user);
         }
+
+        if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
+                && user.isManagedProfile()) {
+            // Send broadcast to notify system that the user removed was a
+            // managed user.
+            sendProfileRemovedBroadcast(user.profileGroupId, user.id);
+        }
+
         if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
         int res;
         try {
@@ -1151,7 +1185,6 @@
         // wiping the user's system directory and removing from the user list
         long ident = Binder.clearCallingIdentity();
         try {
-            final boolean isManaged = getUserInfo(userHandle).isManagedProfile();
             Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
             addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
             mContext.sendOrderedBroadcastAsUser(addedIntent, UserHandle.ALL,
@@ -1172,11 +1205,6 @@
                                             removeUserStateLocked(userHandle);
                                         }
                                     }
-                                    // Send broadcast to notify system that the user removed was a
-                                    // managed user.
-                                    if (isManaged) {
-                                        sendProfileRemovedBroadcast(userHandle);
-                                    }
                                 }
                             }.start();
                         }
@@ -1228,11 +1256,11 @@
         parent.delete();
     }
 
-    private void sendProfileRemovedBroadcast(int userHandle) {
+    private void sendProfileRemovedBroadcast(int parentUserId, int removedUserId) {
         Intent managedProfileIntent = new Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED);
-        managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(userHandle));
-        // Note: This makes an assumption that the parent owner is user 0.
-        mContext.sendBroadcastAsUser(managedProfileIntent, UserHandle.OWNER, null);
+        managedProfileIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(removedUserId));
+        mContext.sendBroadcastAsUser(managedProfileIntent, new UserHandle(parentUserId), null);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 2d6cc7c..e244bde 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -190,14 +190,14 @@
                         + ", workSource=" + newWorkSource);
             }
             try {
-                mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, monitorType,
-                        newWorkSource, newOwnerPid, newTag, newHistoryTag,
+                mBatteryStats.noteChangeWakelockFromSource(workSource, ownerPid, tag, historyTag,
+                        monitorType, newWorkSource, newOwnerPid, newTag, newHistoryTag,
                         newMonitorType, unimportantForLogging);
             } catch (RemoteException ex) {
                 // Ignore
             }
         } else {
-            onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource);
+            onWakeLockReleased(flags, tag, packageName, ownerUid, ownerPid, workSource, historyTag);
             onWakeLockAcquired(newFlags, newTag, newPackageName, newOwnerUid, newOwnerPid,
                     newWorkSource, newHistoryTag);
         }
@@ -207,7 +207,7 @@
      * Called when a wake lock is released.
      */
     public void onWakeLockReleased(int flags, String tag, String packageName,
-            int ownerUid, int ownerPid, WorkSource workSource) {
+            int ownerUid, int ownerPid, WorkSource workSource, String historyTag) {
         if (DEBUG) {
             Slog.d(TAG, "onWakeLockReleased: flags=" + flags + ", tag=\"" + tag
                     + "\", packageName=" + packageName
@@ -218,9 +218,10 @@
         try {
             final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
             if (workSource != null) {
-                mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, monitorType);
+                mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, historyTag,
+                        monitorType);
             } else {
-                mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, monitorType);
+                mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, historyTag, monitorType);
                 mAppOps.finishOperation(AppOpsManager.getToken(mAppOps),
                         AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName);
             }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 03941c6..f0b7861 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
+import com.android.internal.os.BackgroundThread;
 import com.android.server.BatteryService;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
@@ -400,7 +401,10 @@
     private long mLastWarningAboutUserActivityPermission = Long.MIN_VALUE;
 
     // If true, the device is in low power mode.
-    private static boolean mLowPowerModeEnabled;
+    private boolean mLowPowerModeEnabled;
+
+    private final ArrayList<PowerManagerInternal.LowPowerModeListener> mLowPowerModeListeners
+            = new ArrayList<PowerManagerInternal.LowPowerModeListener>();
 
     private native void nativeInit();
 
@@ -623,11 +627,24 @@
                 Settings.System.SCREEN_BRIGHTNESS_MODE,
                 Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT);
 
-        boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
+        final boolean lowPowerModeEnabled = Settings.Global.getInt(resolver,
                 Settings.Global.LOW_POWER_MODE, 0) != 0;
         if (lowPowerModeEnabled != mLowPowerModeEnabled) {
             powerHintInternal(POWER_HINT_LOW_POWER_MODE, lowPowerModeEnabled ? 1 : 0);
             mLowPowerModeEnabled = lowPowerModeEnabled;
+            BackgroundThread.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    ArrayList<PowerManagerInternal.LowPowerModeListener> listeners;
+                    synchronized (mLock) {
+                        listeners = new ArrayList<PowerManagerInternal.LowPowerModeListener>(
+                                mLowPowerModeListeners);
+                    }
+                    for (int i=0; i<listeners.size(); i++) {
+                        listeners.get(i).onLowPowerModeChanged(lowPowerModeEnabled);
+                    }
+                }
+            });
         }
 
         mDirty |= DIRTY_SETTINGS;
@@ -812,8 +829,9 @@
     private void notifyWakeLockReleasedLocked(WakeLock wakeLock) {
         if (mSystemReady && wakeLock.mNotifiedAcquired) {
             wakeLock.mNotifiedAcquired = false;
-            mNotifier.onWakeLockReleased(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName,
-                    wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource);
+            mNotifier.onWakeLockReleased(wakeLock.mFlags, wakeLock.mTag,
+                    wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid,
+                    wakeLock.mWorkSource, wakeLock.mHistoryTag);
         }
     }
 
@@ -2972,6 +2990,20 @@
         }
 
         @Override
+        public boolean getLowPowerModeEnabled() {
+            synchronized (mLock) {
+                return mLowPowerModeEnabled;
+            }
+        }
+
+        @Override
+        public void registerLowPowerModeObserver(LowPowerModeListener listener) {
+            synchronized (mLock) {
+                mLowPowerModeListeners.add(listener);
+            }
+        }
+
+        @Override
         public void setPolicy(WindowManagerPolicy policy) {
             PowerManagerService.this.setPolicy(policy);
         }
diff --git a/services/core/java/com/android/server/task/StateChangedListener.java b/services/core/java/com/android/server/task/StateChangedListener.java
index a87bf95..db2d4ee 100644
--- a/services/core/java/com/android/server/task/StateChangedListener.java
+++ b/services/core/java/com/android/server/task/StateChangedListener.java
@@ -19,9 +19,9 @@
 import com.android.server.task.controllers.TaskStatus;
 
 /**
- * Interface through which a {@link StateController} informs the
- * {@link com.android.server.task.TaskManagerService} that there are some tasks potentially ready
- * to be run.
+ * Interface through which a {@link com.android.server.task.controllers.StateController} informs
+ * the {@link com.android.server.task.TaskManagerService} that there are some tasks potentially
+ * ready to be run.
  */
 public interface StateChangedListener {
     /**
diff --git a/services/core/java/com/android/server/task/TaskCompletedListener.java b/services/core/java/com/android/server/task/TaskCompletedListener.java
new file mode 100644
index 0000000..0210442
--- /dev/null
+++ b/services/core/java/com/android/server/task/TaskCompletedListener.java
@@ -0,0 +1,38 @@
+/*
+ * 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
+ */
+
+package com.android.server.task;
+
+/**
+ * Used for communication between {@link com.android.server.task.TaskServiceContext} and the
+ * {@link com.android.server.task.TaskManagerService}.
+ */
+public interface TaskCompletedListener {
+
+    /**
+     * Callback for when a task is completed.
+     * @param needsReschedule Whether the implementing class should reschedule this task.
+     */
+    public void onTaskCompleted(int serviceToken, int taskId, boolean needsReschedule);
+
+    /**
+     * Callback for when the implementing class needs to clean up the
+     * {@link com.android.server.task.TaskServiceContext}. The scheduler can get this callback
+     * several times if the TaskServiceContext got into a bad state (for e.g. the client crashed
+     * and it needs to clean up).
+     */
+    public void onAllTasksCompleted(int serviceToken);
+}
diff --git a/services/core/java/com/android/server/task/TaskList.java b/services/core/java/com/android/server/task/TaskList.java
deleted file mode 100644
index d2b8440..0000000
--- a/services/core/java/com/android/server/task/TaskList.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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
- */
-
-package com.android.server.task;
-
-import android.content.ComponentName;
-import android.content.Task;
-
-import com.android.server.task.controllers.TaskStatus;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Maintain a list of classes, and accessor methods/logic for these tasks.
- * This class offers the following functionality:
- *     - When a task is added, it will determine if the task requirements have changed (update) and
- *       whether the controllers need to be updated.
- *     - Persists Tasks, figures out when to to rewrite the Task to disk.
- *     - Is threadsafe.
- *     - Handles rescheduling of tasks.
- *       - When a periodic task is executed and must be re-added.
- *       - When a task fails and the client requests that it be retried with backoff.
- */
-public class TaskList {
-
-    final List<TaskStatus> mTasks;
-
-    TaskList() {
-        mTasks = intialiseTaskMapFromDisk();
-    }
-
-    /**
-     * Add a task to the master list, persisting it if necessary.
-     * @param task Task to add.
-     * @param persistable true if the TaskQueue should persist this task to the disk.
-     * @return true if this operation was successful. If false, this task was neither added nor
-     * persisted.
-     */
-    // TODO: implement this when i decide whether i want to key by TaskStatus
-    public boolean add(Task task, boolean persistable) {
-        return true;
-    }
-
-    /**
-     * Remove the provided task. Will also delete the task if it was persisted. Note that this
-     * function does not return the validity of the operation, as we assume a delete will always
-     * succeed.
-     * @param task Task to remove.
-     */
-    public void remove(Task task) {
-
-    }
-
-    /**
-     *
-     * @return
-     */
-    // TODO: Implement this.
-    private List<TaskStatus> intialiseTaskMapFromDisk() {
-        return new ArrayList<TaskStatus>();
-    }
-}
diff --git a/services/core/java/com/android/server/task/TaskManagerService.java b/services/core/java/com/android/server/task/TaskManagerService.java
index 5df4b2a..6d208ff 100644
--- a/services/core/java/com/android/server/task/TaskManagerService.java
+++ b/services/core/java/com/android/server/task/TaskManagerService.java
@@ -17,16 +17,15 @@
 package com.android.server.task;
 
 import android.content.Context;
+import android.content.Task;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.server.task.controllers.TaskStatus;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Responsible for taking tasks representing work to be performed by a client app, and determining
  * based on the criteria specified when that task should be run against the client application's
@@ -34,25 +33,29 @@
  * @hide
  */
 public class TaskManagerService extends com.android.server.SystemService
-        implements StateChangedListener {
+        implements StateChangedListener, TaskCompletedListener {
+    static final String TAG = "TaskManager";
 
     /** Master list of tasks. */
-    private final TaskList mTaskList;
+    private final TaskStore mTasks;
+
+    /** Check the pending queue and start any tasks. */
+    static final int MSG_RUN_PENDING = 0;
+    /** Initiate the stop task flow. */
+    static final int MSG_STOP_TASK = 1;
+    /** */
+    static final int MSG_CHECK_TASKS = 2;
 
     /**
      * Track Services that have currently active or pending tasks. The index is provided by
      * {@link TaskStatus#getServiceToken()}
      */
-    private final SparseArray<TaskServiceContext> mPendingTaskServices =
+    private final SparseArray<TaskServiceContext> mActiveServices =
             new SparseArray<TaskServiceContext>();
 
     private final TaskHandler mHandler;
 
     private class TaskHandler extends Handler {
-        /** Check the pending queue and start any tasks. */
-        static final int MSG_RUN_PENDING = 0;
-        /** Initiate the stop task flow. */
-        static final int MSG_STOP_TASK = 1;
 
         public TaskHandler(Looper looper) {
             super(looper);
@@ -67,21 +70,42 @@
                 case MSG_STOP_TASK:
 
                     break;
+                case MSG_CHECK_TASKS:
+                    checkTasks();
+                    break;
             }
         }
 
         /**
-         * Helper to post a message to this handler that will run through the pending queue and
-         * start any tasks it can.
+         * Called when we need to run through the list of all tasks and start/stop executing one or
+         * more of them.
          */
-        void sendRunPendingTasksMessage() {
-            Message m = Message.obtain(this, MSG_RUN_PENDING);
-            m.sendToTarget();
+        private void checkTasks() {
+            synchronized (mTasks) {
+                final SparseArray<TaskStatus> tasks = mTasks.getTasks();
+                for (int i = 0; i < tasks.size(); i++) {
+                    TaskStatus ts = tasks.valueAt(i);
+                    if (ts.isReady() && ! isCurrentlyActive(ts)) {
+                        assignTaskToServiceContext(ts);
+                    }
+                }
+            }
         }
+    }
 
-        void sendOnStopMessage(TaskStatus taskStatus) {
-
-        }
+    /**
+     * Entry point from client to schedule the provided task.
+     * This will add the task to the
+     * @param task Task object containing execution parameters
+     * @param userId The id of the user this task is for.
+     * @param uId The package identifier of the application this task is for.
+     * @param canPersistTask Whether or not the client has the appropriate permissions for persisting
+     *                    of this task.
+     * @return Result of this operation. See <code>TaskManager#RESULT_*</code> return codes.
+     */
+    public int schedule(Task task, int userId, int uId, boolean canPersistTask) {
+        TaskStatus taskStatus = mTasks.addNewTaskForUser(task, userId, uId, canPersistTask);
+        return 0;
     }
 
     /**
@@ -95,7 +119,7 @@
      */
     public TaskManagerService(Context context) {
         super(context);
-        mTaskList = new TaskList();
+        mTasks = new TaskStore(context);
         mHandler = new TaskHandler(context.getMainLooper());
     }
 
@@ -104,20 +128,18 @@
 
     }
 
+    // StateChangedListener implementations.
+
     /**
-     * Offboard work to our handler thread as quickly as possible, b/c this call is probably being
+     * Off-board work to our handler thread as quickly as possible, b/c this call is probably being
      * made on the main thread.
-     * @param taskStatus The state of the task which has changed.
+     * For now this takes the task and if it's ready to run it will run it. In future we might not
+     * provide the task, so that the StateChangedListener has to run through its list of tasks to
+     * see which are ready. This will further decouple the controllers from the execution logic.
      */
     @Override
     public void onTaskStateChanged(TaskStatus taskStatus) {
-        if (taskStatus.isReady()) {
-
-        } else {
-            if (mPendingTaskServices.get(taskStatus.getServiceToken()) != null) {
-                // The task is either pending or being executed, which we have to cancel.
-            }
-        }
+        postCheckTasksMessage();
 
     }
 
@@ -125,4 +147,60 @@
     public void onTaskDeadlineExpired(TaskStatus taskStatus) {
 
     }
+
+    // TaskCompletedListener implementations.
+
+    /**
+     * A task just finished executing. We fetch the
+     * {@link com.android.server.task.controllers.TaskStatus} from the store and depending on
+     * whether we want to reschedule we readd it to the controllers.
+     * @param serviceToken key for the service context in {@link #mActiveServices}.
+     * @param taskId Id of the task that is complete.
+     * @param needsReschedule Whether the implementing class should reschedule this task.
+     */
+    @Override
+    public void onTaskCompleted(int serviceToken, int taskId, boolean needsReschedule) {
+        final TaskServiceContext serviceContext = mActiveServices.get(serviceToken);
+        if (serviceContext == null) {
+            Log.e(TAG, "Task completed for invalid service context; " + serviceToken);
+            return;
+        }
+
+    }
+
+    @Override
+    public void onAllTasksCompleted(int serviceToken) {
+        
+    }
+
+    private void assignTaskToServiceContext(TaskStatus ts) {
+        TaskServiceContext serviceContext =
+                mActiveServices.get(ts.getServiceToken());
+        if (serviceContext == null) {
+            serviceContext = new TaskServiceContext(this, mHandler.getLooper(), ts);
+            mActiveServices.put(ts.getServiceToken(), serviceContext);
+        }
+        serviceContext.addPendingTask(ts);
+    }
+
+    /**
+     * @param ts TaskStatus we are querying against.
+     * @return Whether or not the task represented by the status object is currently being run or
+     * is pending.
+     */
+    private boolean isCurrentlyActive(TaskStatus ts) {
+        TaskServiceContext serviceContext = mActiveServices.get(ts.getServiceToken());
+        if (serviceContext == null) {
+            return false;
+        }
+        return serviceContext.hasTaskPending(ts);
+    }
+
+    /**
+     * Post a message to {@link #mHandler} to run through the list of tasks and start/stop any that
+     * are eligible.
+     */
+    private void postCheckTasksMessage() {
+        mHandler.obtainMessage(MSG_CHECK_TASKS).sendToTarget();
+    }
 }
diff --git a/services/core/java/com/android/server/task/TaskServiceContext.java b/services/core/java/com/android/server/task/TaskServiceContext.java
index 65c6fa5..b51cbb3 100644
--- a/services/core/java/com/android/server/task/TaskServiceContext.java
+++ b/services/core/java/com/android/server/task/TaskServiceContext.java
@@ -16,79 +16,500 @@
 
 package com.android.server.task;
 
+import android.app.ActivityManager;
 import android.app.task.ITaskCallback;
 import android.app.task.ITaskService;
+import android.app.task.TaskParams;
 import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
 import android.content.ServiceConnection;
-import android.content.Task;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.WorkSource;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
 
 import com.android.server.task.controllers.TaskStatus;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 /**
  * Maintains information required to bind to a {@link android.app.task.TaskService}. This binding
- * can then be reused to start concurrent tasks on the TaskService. Information here is unique
- * within this service.
+ * is reused to start concurrent tasks on the TaskService. Information here is unique
+ * to the service.
  * Functionality provided by this class:
  *     - Managages wakelock for the service.
  *     - Sends onStartTask() and onStopTask() messages to client app, and handles callbacks.
  *     -
  */
 public class TaskServiceContext extends ITaskCallback.Stub implements ServiceConnection {
+    private static final String TAG = "TaskServiceContext";
+    /** Define the maximum # of tasks allowed to run on a service at once. */
+    private static final int defaultMaxActiveTasksPerService =
+            ActivityManager.isLowRamDeviceStatic() ? 1 : 3;
+    /** Amount of time a task is allowed to execute for before being considered timed-out. */
+    private static final long EXECUTING_TIMESLICE_MILLIS = 5 * 60 * 1000;
+    /** Amount of time the TaskManager will wait for a response from an app for a message. */
+    private static final long OP_TIMEOUT_MILLIS = 8 * 1000;
+    /** String prefix for all wakelock names. */
+    private static final String TM_WAKELOCK_PREFIX = "*task*/";
 
+    private static final String[] VERB_STRINGS = {
+            "VERB_STARTING", "VERB_EXECUTING", "VERB_STOPPING", "VERB_PENDING"
+    };
+
+    // States that a task occupies while interacting with the client.
+    private static final int VERB_STARTING = 0;
+    private static final int VERB_EXECUTING = 1;
+    private static final int VERB_STOPPING = 2;
+    private static final int VERB_PENDING = 3;
+
+    // Messages that result from interactions with the client service.
+    /** System timed out waiting for a response. */
+    private static final int MSG_TIMEOUT = 0;
+    /** Received a callback from client. */
+    private static final int MSG_CALLBACK = 1;
+    /** Run through list and start any ready tasks.*/
+    private static final int MSG_CHECK_PENDING = 2;
+    /** Cancel an active task. */
+    private static final int MSG_CANCEL = 3;
+    /** Add a pending task. */
+    private static final int MSG_ADD_PENDING = 4;
+    /** Client crashed, so we need to wind things down. */
+    private static final int MSG_SHUTDOWN = 5;
+
+    /** Used to identify this task service context when communicating with the TaskManager. */
+    final int token;
     final ComponentName component;
-    int uid;
+    final int userId;
     ITaskService service;
+    private final Handler mCallbackHandler;
+    /** Tasks that haven't been sent to the client for execution yet. */
+    private final SparseArray<ActiveTask> mPending;
+    /** Used for service binding, etc. */
+    private final Context mContext;
+    /** Make callbacks to {@link TaskManagerService} to inform on task completion status. */
+    final private TaskCompletedListener mCompletedListener;
+    private final PowerManager.WakeLock mWakeLock;
 
     /** Whether this service is actively bound. */
     boolean mBound;
 
-    TaskServiceContext(Task task) {
-        this.component = task.getService();
-    }
-
-    public void stopTask() {
-
-    }
-
-    public void startTask(Task task) {
-
+    TaskServiceContext(TaskManagerService taskManager, Looper looper, TaskStatus taskStatus) {
+        mContext = taskManager.getContext();
+        this.component = taskStatus.getServiceComponent();
+        this.token = taskStatus.getServiceToken();
+        this.userId = taskStatus.getUserId();
+        mCallbackHandler = new TaskServiceHandler(looper);
+        mPending = new SparseArray<ActiveTask>();
+        mCompletedListener = taskManager;
+        final PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                TM_WAKELOCK_PREFIX + component.getPackageName());
+        mWakeLock.setWorkSource(new WorkSource(taskStatus.getUid()));
+        mWakeLock.setReferenceCounted(false);
     }
 
     @Override
     public void taskFinished(int taskId, boolean reschedule) {
-
+        mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, reschedule ? 1 : 0)
+                .sendToTarget();
     }
 
     @Override
-    public void acknowledgeStopMessage(int taskId) {
-
+    public void acknowledgeStopMessage(int taskId, boolean reschedule) {
+        mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, reschedule ? 1 : 0)
+                .sendToTarget();
     }
 
     @Override
-    public void acknowledgeStartMessage(int taskId) {
+    public void acknowledgeStartMessage(int taskId, boolean ongoing) {
+        mCallbackHandler.obtainMessage(MSG_CALLBACK, taskId, ongoing ? 1 : 0).sendToTarget();
+    }
 
+    /**
+     * Queue up this task to run on the client. This will execute the task as quickly as possible.
+     * @param ts Status of the task to run.
+     */
+    public void addPendingTask(TaskStatus ts) {
+        final TaskParams params = new TaskParams(ts.getTaskId(), ts.getExtras(), this);
+        final ActiveTask newTask = new ActiveTask(params, VERB_PENDING);
+        mCallbackHandler.obtainMessage(MSG_ADD_PENDING, newTask).sendToTarget();
+        if (!mBound) {
+            Intent intent = new Intent().setComponent(component);
+            boolean binding = mContext.bindServiceAsUser(intent, this,
+                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
+                    new UserHandle(userId));
+            if (!binding) {
+                Log.e(TAG, component.getShortClassName() + " unavailable.");
+                cancelPendingTask(ts);
+            }
+        }
+    }
+
+    /**
+     * Called externally when a task that was scheduled for execution should be cancelled.
+     * @param ts The status of the task to cancel.
+     */
+    public void cancelPendingTask(TaskStatus ts) {
+        mCallbackHandler.obtainMessage(MSG_CANCEL, ts.getTaskId(), -1 /* arg2 */)
+                .sendToTarget();
+    }
+
+    /**
+     * MSG_TIMEOUT is sent with the {@link com.android.server.task.TaskServiceContext.ActiveTask}
+     * set in the {@link Message#obj} field. This makes it easier to remove timeouts for a given
+     * ActiveTask.
+     * @param op Operation that is taking place.
+     */
+    private void scheduleOpTimeOut(ActiveTask op) {
+        mCallbackHandler.removeMessages(MSG_TIMEOUT, op);
+
+        final long timeoutMillis = (op.verb == VERB_EXECUTING) ?
+                EXECUTING_TIMESLICE_MILLIS : OP_TIMEOUT_MILLIS;
+        if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+            Slog.d(TAG, "Scheduling time out for '" + component.getShortClassName() + "' tId: " +
+                    op.params.getTaskId() + ", in " + (timeoutMillis / 1000) + " s");
+        }
+        Message m = mCallbackHandler.obtainMessage(MSG_TIMEOUT, op);
+        mCallbackHandler.sendMessageDelayed(m, timeoutMillis);
     }
 
     /**
      * @return true if this task is pending or active within this context.
      */
     public boolean hasTaskPending(TaskStatus taskStatus) {
-        return true;
+        synchronized (mPending) {
+            return mPending.get(taskStatus.getTaskId()) != null;
+        }
     }
 
     public boolean isBound() {
         return mBound;
     }
 
+    /**
+     * We acquire/release the wakelock on onServiceConnected/unbindService. This mirrors the work
+     * we intend to send to the client - we stop sending work when the service is unbound so until
+     * then we keep the wakelock.
+     * @param name The concrete component name of the service that has
+     * been connected.
+     * @param service The IBinder of the Service's communication channel,
+     */
     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
-
         mBound = true;
+        this.service = ITaskService.Stub.asInterface(service);
+        // Remove all timeouts. We've just connected to the client so there are no other
+        // MSG_TIMEOUTs at this point.
+        mCallbackHandler.removeMessages(MSG_TIMEOUT);
+        mWakeLock.acquire();
+        mCallbackHandler.obtainMessage(MSG_CHECK_PENDING).sendToTarget();
     }
 
+    /**
+     * When the client service crashes we can have a couple tasks executing, in various stages of
+     * undress. We'll cancel all of them and request that they be rescheduled.
+     * @param name The concrete component name of the service whose
+     */
     @Override
     public void onServiceDisconnected(ComponentName name) {
-        mBound = false;
+        // Service disconnected... probably client crashed.
+        startShutdown();
+    }
+
+    /**
+     * We don't just shutdown outright - we make sure the scheduler isn't going to send us any more
+     * tasks, then we do the shutdown.
+     */
+    private void startShutdown() {
+        mCompletedListener.onAllTasksCompleted(token);
+        mCallbackHandler.obtainMessage(MSG_SHUTDOWN).sendToTarget();
+    }
+
+    /** Tracks a task across its various state changes. */
+    private static class ActiveTask {
+        final TaskParams params;
+        int verb;
+        AtomicBoolean cancelled = new AtomicBoolean();
+
+        ActiveTask(TaskParams params, int verb) {
+            this.params = params;
+            this.verb = verb;
+        }
+
+        @Override
+        public String toString() {
+            return params.getTaskId() + " " + VERB_STRINGS[verb];
+        }
+    }
+
+    /**
+     * Handles the lifecycle of the TaskService binding/callbacks, etc. The convention within this
+     * class is to append 'H' to each function name that can only be called on this handler. This
+     * isn't strictly necessary because all of these functions are private, but helps clarity.
+     */
+    private class TaskServiceHandler extends Handler {
+        TaskServiceHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message message) {
+            switch (message.what) {
+                case MSG_ADD_PENDING:
+                    if (message.obj != null) {
+                        ActiveTask pendingTask = (ActiveTask) message.obj;
+                        mPending.put(pendingTask.params.getTaskId(), pendingTask);
+                    }
+                    // fall through.
+                case MSG_CHECK_PENDING:
+                    checkPendingTasksH();
+                    break;
+                case MSG_CALLBACK:
+                    ActiveTask receivedCallback = mPending.get(message.arg1);
+                    removeMessages(MSG_TIMEOUT, receivedCallback);
+
+                    if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+                        Log.d(TAG, "MSG_CALLBACK of : " + receivedCallback);
+                    }
+
+                    if (receivedCallback.verb == VERB_STARTING) {
+                        final boolean workOngoing = message.arg2 == 1;
+                        handleStartedH(receivedCallback, workOngoing);
+                    } else if (receivedCallback.verb == VERB_EXECUTING ||
+                            receivedCallback.verb == VERB_STOPPING) {
+                        final boolean reschedule = message.arg2 == 1;
+                        handleFinishedH(receivedCallback, reschedule);
+                    } else {
+                        if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+                            Log.d(TAG, "Unrecognised callback: " + receivedCallback);
+                        }
+                    }
+                    break;
+                case MSG_CANCEL:
+                    ActiveTask cancelled = mPending.get(message.arg1);
+                    handleCancelH(cancelled);
+                    break;
+                case MSG_TIMEOUT:
+                    // Timeout msgs have the ActiveTask ref so we can remove them easily.
+                    handleOpTimeoutH((ActiveTask) message.obj);
+                    break;
+                case MSG_SHUTDOWN:
+                    handleShutdownH();
+                    break;
+                default:
+                    Log.e(TAG, "Unrecognised message: " + message);
+            }
+        }
+
+        /**
+         * State behaviours.
+         * VERB_STARTING   -> Successful start, change task to VERB_EXECUTING and post timeout.
+         *     _PENDING    -> Error
+         *     _EXECUTING  -> Error
+         *     _STOPPING   -> Error
+         */
+        private void handleStartedH(ActiveTask started, boolean workOngoing) {
+            switch (started.verb) {
+                case VERB_STARTING:
+                    started.verb = VERB_EXECUTING;
+                    if (!workOngoing) {
+                        // Task is finished already so fast-forward to handleFinished.
+                        handleFinishedH(started, false);
+                        return;
+                    } else if (started.cancelled.get()) {
+                        // Cancelled *while* waiting for acknowledgeStartMessage from client.
+                        handleCancelH(started);
+                        return;
+                    } else {
+                        scheduleOpTimeOut(started);
+                    }
+                    break;
+                default:
+                    Log.e(TAG, "Handling started task but task wasn't starting! " + started);
+                    return;
+            }
+        }
+
+        /**
+         * VERB_EXECUTING  -> Client called taskFinished(), clean up and notify done.
+         *     _STOPPING   -> Successful finish, clean up and notify done.
+         *     _STARTING   -> Error
+         *     _PENDING    -> Error
+         */
+        private void handleFinishedH(ActiveTask executedTask, boolean reschedule) {
+            switch (executedTask.verb) {
+                case VERB_EXECUTING:
+                case VERB_STOPPING:
+                    closeAndCleanupTaskH(executedTask, reschedule);
+                    break;
+                default:
+                    Log.e(TAG, "Got an execution complete message for a task that wasn't being" +
+                            "executed. " + executedTask);
+            }
+        }
+
+        /**
+         * A task can be in various states when a cancel request comes in:
+         * VERB_PENDING    -> Remove from queue.
+         *     _STARTING   -> Mark as cancelled and wait for {@link #acknowledgeStartMessage(int)}.
+         *     _EXECUTING  -> call {@link #sendStopMessageH}}.
+         *     _ENDING     -> No point in doing anything here, so we ignore.
+         */
+        private void handleCancelH(ActiveTask cancelledTask) {
+            switch (cancelledTask.verb) {
+                case VERB_PENDING:
+                    mPending.remove(cancelledTask.params.getTaskId());
+                    break;
+                case VERB_STARTING:
+                    cancelledTask.cancelled.set(true);
+                    break;
+                case VERB_EXECUTING:
+                    cancelledTask.verb = VERB_STOPPING;
+                    sendStopMessageH(cancelledTask);
+                    break;
+                case VERB_STOPPING:
+                    // Nada.
+                    break;
+                default:
+                    Log.e(TAG, "Cancelling a task without a valid verb: " + cancelledTask);
+                    break;
+            }
+        }
+
+        /**
+         * This TaskServiceContext is shutting down. Remove all the tasks from the pending queue
+         * and reschedule them as if they had failed.
+         * Before posting this message, caller must invoke
+         * {@link com.android.server.task.TaskCompletedListener#onAllTasksCompleted(int)}.
+         */
+        private void handleShutdownH() {
+            for (int i = 0; i < mPending.size(); i++) {
+                ActiveTask at = mPending.valueAt(i);
+                closeAndCleanupTaskH(at, true /* needsReschedule */);
+            }
+            mWakeLock.release();
+            mContext.unbindService(TaskServiceContext.this);
+            service = null;
+            mBound = false;
+        }
+
+        /**
+         * MSG_TIMEOUT gets processed here.
+         * @param timedOutTask The task that timed out.
+         */
+        private void handleOpTimeoutH(ActiveTask timedOutTask) {
+            if (Log.isLoggable(TaskManagerService.TAG, Log.DEBUG)) {
+                Log.d(TAG, "MSG_TIMEOUT of " + component.getShortClassName() + " : "
+                        + timedOutTask.params.getTaskId());
+            }
+
+            final int taskId = timedOutTask.params.getTaskId();
+            switch (timedOutTask.verb) {
+                case VERB_STARTING:
+                    // Client unresponsive - wedged or failed to respond in time. We don't really
+                    // know what happened so let's log it and notify the TaskManager
+                    // FINISHED/NO-RETRY.
+                    Log.e(TAG, "No response from client for onStartTask '" +
+                            component.getShortClassName() + "' tId: " + taskId);
+                    closeAndCleanupTaskH(timedOutTask, false /* needsReschedule */);
+                    break;
+                case VERB_STOPPING:
+                    // At least we got somewhere, so fail but ask the TaskManager to reschedule.
+                    Log.e(TAG, "No response from client for onStopTask, '" +
+                            component.getShortClassName() + "' tId: " + taskId);
+                    closeAndCleanupTaskH(timedOutTask, true /* needsReschedule */);
+                    break;
+                case VERB_EXECUTING:
+                    // Not an error - client ran out of time.
+                    Log.i(TAG, "Client timed out while executing (no taskFinished received)." +
+                            " Reporting failure and asking for reschedule. "  +
+                            component.getShortClassName() + "' tId: " + taskId);
+                    sendStopMessageH(timedOutTask);
+                    break;
+                default:
+                    Log.e(TAG, "Handling timeout for an unknown active task state: "
+                            + timedOutTask);
+                    return;
+            }
+        }
+
+        /**
+         * Called on the handler thread. Checks the state of the pending queue and starts the task
+         * if it can. The task only starts if there is capacity on the service.
+         */
+        private void checkPendingTasksH() {
+            if (!mBound) {
+                return;
+            }
+            for (int i = 0; i < mPending.size() && i < defaultMaxActiveTasksPerService; i++) {
+                ActiveTask at = mPending.valueAt(i);
+                if (at.verb != VERB_PENDING) {
+                    continue;
+                }
+                sendStartMessageH(at);
+            }
+        }
+
+        /**
+         * Already running, need to stop. Rund on handler.
+         * @param stoppingTask Task we are sending onStopMessage for. This task will be moved from
+         *                     VERB_EXECUTING -> VERB_STOPPING.
+         */
+        private void sendStopMessageH(ActiveTask stoppingTask) {
+            mCallbackHandler.removeMessages(MSG_TIMEOUT, stoppingTask);
+            if (stoppingTask.verb != VERB_EXECUTING) {
+                Log.e(TAG, "Sending onStopTask for a task that isn't started. " + stoppingTask);
+                // TODO: Handle error?
+                return;
+            }
+            try {
+                service.stopTask(stoppingTask.params);
+                stoppingTask.verb = VERB_STOPPING;
+                scheduleOpTimeOut(stoppingTask);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error sending onStopTask to client.", e);
+                closeAndCleanupTaskH(stoppingTask, false);
+            }
+        }
+
+        /** Start the task on the service. */
+        private void sendStartMessageH(ActiveTask pendingTask) {
+            if (pendingTask.verb != VERB_PENDING) {
+                Log.e(TAG, "Sending onStartTask for a task that isn't pending. " + pendingTask);
+                // TODO: Handle error?
+            }
+            try {
+                service.startTask(pendingTask.params);
+                pendingTask.verb = VERB_STARTING;
+                scheduleOpTimeOut(pendingTask);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error sending onStart message to '" + component.getShortClassName()
+                        + "' ", e);
+            }
+        }
+
+        /**
+         * The provided task has finished, either by calling
+         * {@link android.app.task.TaskService#taskFinished(android.app.task.TaskParams, boolean)}
+         * or from acknowledging the stop message we sent. Either way, we're done tracking it and
+         * we want to clean up internally.
+         */
+        private void closeAndCleanupTaskH(ActiveTask completedTask, boolean reschedule) {
+            removeMessages(MSG_TIMEOUT, completedTask);
+            mPending.remove(completedTask.params.getTaskId());
+            if (mPending.size() == 0) {
+                startShutdown();
+            }
+            mCompletedListener.onTaskCompleted(token, completedTask.params.getTaskId(), reschedule);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/task/TaskStore.java b/services/core/java/com/android/server/task/TaskStore.java
new file mode 100644
index 0000000..3bfc8a5
--- /dev/null
+++ b/services/core/java/com/android/server/task/TaskStore.java
@@ -0,0 +1,103 @@
+/*
+ * 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
+ */
+
+package com.android.server.task;
+
+import android.content.Context;
+import android.content.Task;
+import android.util.SparseArray;
+
+import com.android.server.task.controllers.TaskStatus;
+
+/**
+ * Maintain a list of classes, and accessor methods/logic for these tasks.
+ * This class offers the following functionality:
+ *     - When a task is added, it will determine if the task requirements have changed (update) and
+ *       whether the controllers need to be updated.
+ *     - Persists Tasks, figures out when to to rewrite the Task to disk.
+ *     - Is threadsafe.
+ *     - Handles rescheduling of tasks.
+ *       - When a periodic task is executed and must be re-added.
+ *       - When a task fails and the client requests that it be retried with backoff.
+ *       - This class is <strong>not</strong> thread-safe.
+ */
+public class TaskStore {
+
+    /**
+     * Master list, indexed by {@link com.android.server.task.controllers.TaskStatus#hashCode()}.
+     */
+    final SparseArray<TaskStatus> mTasks;
+    final Context mContext;
+
+    TaskStore(Context context) {
+        mTasks = intialiseTaskMapFromDisk();
+        mContext = context;
+    }
+
+    /**
+     * Add a task to the master list, persisting it if necessary.
+     * Will first check to see if the task already exists. If so, it will replace it.
+     * {@link android.content.pm.PackageManager} is queried to see if the calling package has
+     * permission to
+     * @param task Task to add.
+     * @return The initialised TaskStatus object if this operation was successful, null if it
+     * failed.
+     */
+    public TaskStatus addNewTaskForUser(Task task, int userId, int uId,
+                                                     boolean canPersistTask) {
+        TaskStatus taskStatus = TaskStatus.getForTaskAndUser(task, userId, uId);
+        if (canPersistTask && task.isPeriodic()) {
+            if (writeStatusToDisk()) {
+                mTasks.put(taskStatus.hashCode(), taskStatus);
+            }
+        }
+        return taskStatus;
+    }
+
+    /**
+     * Remove the provided task. Will also delete the task if it was persisted. Note that this
+     * function does not return the validity of the operation, as we assume a delete will always
+     * succeed.
+     * @param task Task to remove.
+     */
+    public void remove(Task task) {
+
+    }
+
+    /**
+     * Every time the state changes we write all the tasks in one swathe, instead of trying to
+     * track incremental changes.
+     */
+    private boolean writeStatusToDisk() {
+        return true;
+    }
+
+    /**
+     *
+     * @return
+     */
+    // TODO: Implement this.
+    private SparseArray<TaskStatus> intialiseTaskMapFromDisk() {
+        return new SparseArray<TaskStatus>();
+    }
+
+    /**
+     * @return The live array of TaskStatus objects.
+     */
+    public SparseArray<TaskStatus> getTasks() {
+        return mTasks;
+    }
+}
diff --git a/services/core/java/com/android/server/task/controllers/ConnectivityController.java b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
index 5cca77c..6a4e1f3 100644
--- a/services/core/java/com/android/server/task/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/task/controllers/ConnectivityController.java
@@ -41,6 +41,11 @@
     private final BroadcastReceiver mConnectivityChangedReceiver =
             new ConnectivityChangedReceiver();
 
+    /** Track whether the latest active network is metered. */
+    private boolean mMetered;
+    /** Track whether the latest active network is connected. */
+    private boolean mConnectivity;
+
     public ConnectivityController(TaskManagerService service) {
         super(service);
         // Register connectivity changed BR.
@@ -53,6 +58,8 @@
     @Override
     public void maybeTrackTaskState(TaskStatus taskStatus) {
         if (taskStatus.hasConnectivityConstraint() || taskStatus.hasMeteredConstraint()) {
+            taskStatus.connectivityConstraintSatisfied.set(mConnectivity);
+            taskStatus.meteredConstraintSatisfied.set(mMetered);
             mTrackedTasks.add(taskStatus);
         }
     }
@@ -63,19 +70,16 @@
     }
 
     /**
-     * @param isConnected Whether the active network is connected for the given uid
-     * @param isMetered Whether the active network is metered for the given uid. This is
-     *                  necessarily false if <code>isConnected</code> is false.
      * @param userId Id of the user for whom we are updating the connectivity state.
      */
-    private void updateTrackedTasks(boolean isConnected, boolean isMetered, int userId) {
+    private void updateTrackedTasks(int userId) {
         for (TaskStatus ts : mTrackedTasks) {
             if (ts.userId != userId) {
                 continue;
             }
-            boolean prevIsConnected = ts.connectivityConstraintSatisfied.getAndSet(isConnected);
-            boolean prevIsMetered = ts.meteredConstraintSatisfied.getAndSet(isMetered);
-            if (prevIsConnected != isConnected || prevIsMetered != isMetered) {
+            boolean prevIsConnected = ts.connectivityConstraintSatisfied.getAndSet(mConnectivity);
+            boolean prevIsMetered = ts.meteredConstraintSatisfied.getAndSet(mMetered);
+            if (prevIsConnected != mConnectivity || prevIsMetered != mMetered) {
                     mStateChangedListener.onTaskStateChanged(ts);
             }
         }
@@ -83,12 +87,13 @@
 
     class ConnectivityChangedReceiver extends BroadcastReceiver {
         /**
-         * We'll receive connectivity changes for each user here, which we'll process independently.
+         * We'll receive connectivity changes for each user here, which we process independently.
          * We are only interested in the active network here. We're only interested in the active
          * network, b/c the end result of this will be for apps to try to hit the network.
          * @param context The Context in which the receiver is running.
          * @param intent The Intent being received.
          */
+        // TODO: Test whether this will be called twice for each user.
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
@@ -103,13 +108,13 @@
                 // This broadcast gets sent a lot, only update if the active network has changed.
                 if (activeNetwork.getType() == networkType) {
                     final int userid = context.getUserId();
-                    boolean isMetered = false;
-                    boolean isConnected =
+                    mMetered = false;
+                    mConnectivity =
                             !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
-                    if (isConnected) {  // No point making the call if we know there's no conn.
-                        isMetered = connManager.isActiveNetworkMetered();
+                    if (mConnectivity) {  // No point making the call if we know there's no conn.
+                        mMetered = connManager.isActiveNetworkMetered();
                     }
-                    updateTrackedTasks(isConnected, isMetered, userid);
+                    updateTrackedTasks(userid);
                 }
             } else {
                 Log.w(TAG, "Unrecognised action in intent: " + action);
diff --git a/services/core/java/com/android/server/task/controllers/IdleController.java b/services/core/java/com/android/server/task/controllers/IdleController.java
new file mode 100644
index 0000000..a319a31
--- /dev/null
+++ b/services/core/java/com/android/server/task/controllers/IdleController.java
@@ -0,0 +1,180 @@
+/*
+ * 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
+ */
+
+package com.android.server.task.controllers;
+
+import java.util.ArrayList;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.SystemClock;
+import android.util.Slog;
+
+import com.android.server.task.TaskManagerService;
+
+public class IdleController extends StateController {
+    private static final String TAG = "IdleController";
+    private static final boolean DEBUG = false;
+
+    // Policy: we decide that we're "idle" if the device has been unused /
+    // screen off or dreaming for at least this long
+    private static final long INACTIVITY_IDLE_THRESHOLD = 71 * 60 * 1000; // millis; 71 min
+    private static final long IDLE_WINDOW_SLOP = 5 * 60 * 1000; // 5 minute window, to be nice
+
+    private static final String ACTION_TRIGGER_IDLE =
+            "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE";
+
+    final ArrayList<TaskStatus> mTrackedTasks = new ArrayList<TaskStatus>();
+    IdlenessTracker mIdleTracker;
+
+    // Singleton factory
+    private static Object sCreationLock = new Object();
+    private static volatile IdleController sController;
+
+    public IdleController getController(TaskManagerService service) {
+        synchronized (sCreationLock) {
+            if (sController == null) {
+                sController = new IdleController(service);
+            }
+            return sController;
+        }
+    }
+
+    private IdleController(TaskManagerService service) {
+        super(service);
+        initIdleStateTracking();
+    }
+
+    /**
+     * StateController interface
+     */
+    @Override
+    public void maybeTrackTaskState(TaskStatus taskStatus) {
+        if (taskStatus.hasIdleConstraint()) {
+            synchronized (mTrackedTasks) {
+                mTrackedTasks.add(taskStatus);
+                taskStatus.idleConstraintSatisfied.set(mIdleTracker.isIdle());
+            }
+        }
+    }
+
+    @Override
+    public void removeTaskStateIfTracked(TaskStatus taskStatus) {
+        synchronized (mTrackedTasks) {
+            mTrackedTasks.remove(taskStatus);
+        }
+    }
+
+    /**
+     * Interaction with the task manager service
+     */
+    void reportNewIdleState(boolean isIdle) {
+        synchronized (mTrackedTasks) {
+            for (TaskStatus task : mTrackedTasks) {
+                task.idleConstraintSatisfied.set(isIdle);
+                mStateChangedListener.onTaskStateChanged(task);
+            }
+        }
+    }
+
+    /**
+     * Idle state tracking, and messaging with the task manager when
+     * significant state changes occur
+     */
+    private void initIdleStateTracking() {
+        mIdleTracker = new IdlenessTracker();
+        mIdleTracker.startTracking();
+    }
+
+    class IdlenessTracker extends BroadcastReceiver {
+        private AlarmManager mAlarm;
+        private PendingIntent mIdleTriggerIntent;
+        boolean mIdle;
+
+        public IdlenessTracker() {
+            mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+
+            Intent intent = new Intent(ACTION_TRIGGER_IDLE);
+            intent.setComponent(new ComponentName(mContext, this.getClass()));
+            mIdleTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+
+            // at boot we presume that the user has just "interacted" with the
+            // device in some meaningful way
+            mIdle = false;
+        }
+
+        public boolean isIdle() {
+            return mIdle;
+        }
+
+        public void startTracking() {
+            IntentFilter filter = new IntentFilter();
+
+            // Screen state
+            filter.addAction(Intent.ACTION_SCREEN_ON);
+            filter.addAction(Intent.ACTION_SCREEN_OFF);
+
+            // Dreaming state
+            filter.addAction(Intent.ACTION_DREAMING_STARTED);
+            filter.addAction(Intent.ACTION_DREAMING_STOPPED);
+
+            mContext.registerReceiver(this, filter);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+
+            if (action.equals(Intent.ACTION_SCREEN_ON)
+                    || action.equals(Intent.ACTION_DREAMING_STOPPED)) {
+                // possible transition to not-idle
+                if (mIdle) {
+                    if (DEBUG) {
+                        Slog.v(TAG, "exiting idle : " + action);
+                    }
+                    mAlarm.cancel(mIdleTriggerIntent);
+                    mIdle = false;
+                    reportNewIdleState(mIdle);
+                }
+            } else if (action.equals(Intent.ACTION_SCREEN_OFF)
+                    || action.equals(Intent.ACTION_DREAMING_STARTED)) {
+                // when the screen goes off or dreaming starts, we schedule the
+                // alarm that will tell us when we have decided the device is
+                // truly idle.
+                long when = SystemClock.elapsedRealtime() + INACTIVITY_IDLE_THRESHOLD;
+                if (DEBUG) {
+                    Slog.v(TAG, "Scheduling idle : " + action + " when=" + when);
+                }
+                mAlarm.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                        when, IDLE_WINDOW_SLOP, mIdleTriggerIntent);
+            } else if (action.equals(ACTION_TRIGGER_IDLE)) {
+                // idle time starts now
+                if (!mIdle) {
+                    if (DEBUG) {
+                        Slog.v(TAG, "Idle trigger fired @ " + SystemClock.elapsedRealtime());
+                    }
+                    mIdle = true;
+                    reportNewIdleState(mIdle);
+                }
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/task/controllers/TaskStatus.java b/services/core/java/com/android/server/task/controllers/TaskStatus.java
index 230b049..d96fedc 100644
--- a/services/core/java/com/android/server/task/controllers/TaskStatus.java
+++ b/services/core/java/com/android/server/task/controllers/TaskStatus.java
@@ -18,6 +18,8 @@
 
 import android.content.ComponentName;
 import android.content.Task;
+import android.content.pm.PackageParser;
+import android.os.Bundle;
 import android.os.SystemClock;
 
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -36,7 +38,9 @@
 public class TaskStatus {
     final int taskId;
     final int userId;
-    ComponentName component;
+    final int uId;
+    final ComponentName component;
+    final Bundle extras;
 
     final AtomicBoolean chargingConstraintSatisfied = new AtomicBoolean();
     final AtomicBoolean timeConstraintSatisfied = new AtomicBoolean();
@@ -60,15 +64,17 @@
 
     /** Generate a TaskStatus object for a given task and uid. */
     // TODO: reimplement this to reuse these objects instead of creating a new one each time?
-    static TaskStatus getForTaskAndUid(Task task, int uId) {
-        return new TaskStatus(task, uId);
+    public static TaskStatus getForTaskAndUser(Task task, int userId, int uId) {
+        return new TaskStatus(task, userId, uId);
     }
 
     /** Set up the state of a newly scheduled task. */
-    TaskStatus(Task task, int userId) {
+    TaskStatus(Task task, int userId, int uId) {
         this.taskId = task.getTaskId();
         this.userId = userId;
         this.component = task.getService();
+        this.extras = task.getExtras();
+        this.uId = uId;
 
         hasChargingConstraint = task.isRequireCharging();
         hasIdleConstraint = task.isRequireDeviceIdle();
@@ -94,6 +100,26 @@
         hasConnectivityConstraint = task.getNetworkCapabilities() == Task.NetworkType.ANY;
     }
 
+    public int getTaskId() {
+        return taskId;
+    }
+
+    public ComponentName getServiceComponent() {
+        return component;
+    }
+
+    public int getUserId() {
+        return userId;
+    }
+
+    public int getUid() {
+        return uId;
+    }
+
+    public Bundle getExtras() {
+        return extras;
+    }
+
     boolean hasConnectivityConstraint() {
         return hasConnectivityConstraint;
     }
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index a83fa87..d8d3da1 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -52,7 +52,7 @@
 
     // Trust state
     private boolean mTrusted;
-    private String mMessage;
+    private CharSequence mMessage;
 
     private final Handler mHandler = new Handler() {
         @Override
@@ -60,7 +60,7 @@
             switch (msg.what) {
                 case MSG_ENABLE_TRUST:
                     mTrusted = true;
-                    mMessage = (String) msg.obj;
+                    mMessage = (CharSequence) msg.obj;
                     boolean initiatedByUser = msg.arg1 != 0;
                     // TODO: Handle handle user initiated trust changes.
                     mTrustManagerService.updateTrust(mUserId);
@@ -79,7 +79,8 @@
 
     private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
 
-        public void enableTrust(String userMessage, long durationMs, boolean initiatedByUser) {
+        @Override
+        public void grantTrust(CharSequence userMessage, long durationMs, boolean initiatedByUser) {
             if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
                         + ", initiatedByUser = " + initiatedByUser + ")");
 
@@ -91,6 +92,7 @@
             }
         }
 
+        @Override
         public void revokeTrust() {
             if (DEBUG) Slog.v(TAG, "revokeTrust()");
             mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
@@ -155,7 +157,7 @@
         return mTrusted;
     }
 
-    public String getMessage() {
+    public CharSequence getMessage() {
         return mMessage;
     }
 
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 9061f96..c1b9a33 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -24,11 +24,14 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.Manifest;
+import android.app.admin.DevicePolicyManager;
 import android.app.trust.ITrustListener;
 import android.app.trust.ITrustManager;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
@@ -46,6 +49,7 @@
 import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.Slog;
+import android.util.SparseBooleanArray;
 import android.util.Xml;
 
 import java.io.IOException;
@@ -81,6 +85,8 @@
 
     private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>();
     private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>();
+    private final DevicePolicyReceiver mDevicePolicyReceiver = new DevicePolicyReceiver();
+    private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray();
     private final Context mContext;
 
     private UserManager mUserManager;
@@ -105,8 +111,8 @@
     @Override
     public void onBootPhase(int phase) {
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) {
-            // Listen for package changes
             mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
+            mDevicePolicyReceiver.register(mContext);
             refreshAgentList();
         }
     }
@@ -158,8 +164,13 @@
         mObsoleteAgents.addAll(mActiveAgents);
 
         for (UserInfo userInfo : userInfos) {
+            int disabledFeatures = lockPatternUtils.getDevicePolicyManager()
+                    .getKeyguardDisabledFeatures(null, userInfo.id);
+            boolean disableTrustAgents =
+                    (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
+
             List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id);
-            if (enabledAgents == null) {
+            if (disableTrustAgents || enabledAgents == null) {
                 continue;
             }
             List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT,
@@ -221,8 +232,8 @@
                 // Drain preamble.
             }
             String nodeName = parser.getName();
-            if (!"trust_agent".equals(nodeName)) {
-                Slog.w(TAG, "Meta-data does not start with trust_agent tag");
+            if (!"trust-agent".equals(nodeName)) {
+                Slog.w(TAG, "Meta-data does not start with trust-agent tag");
                 return null;
             }
             TypedArray sa = res
@@ -259,6 +270,9 @@
     // Agent dispatch and aggregation
 
     private boolean aggregateIsTrusted(int userId) {
+        if (!mUserHasAuthenticatedSinceBoot.get(userId)) {
+            return false;
+        }
         for (int i = 0; i < mActiveAgents.size(); i++) {
             AgentInfo info = mActiveAgents.valueAt(i);
             if (info.userId == userId) {
@@ -277,6 +291,11 @@
                 info.agent.onUnlockAttempt(successful);
             }
         }
+
+        if (successful && !mUserHasAuthenticatedSinceBoot.get(userId)) {
+            mUserHasAuthenticatedSinceBoot.put(userId, true);
+            updateTrust(userId);
+        }
     }
 
     // Listeners
@@ -384,4 +403,24 @@
             return true;
         }
     };
+
+    private class DevicePolicyReceiver extends BroadcastReceiver {
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
+                    intent.getAction())) {
+                refreshAgentList();
+            }
+        }
+
+        public void register(Context context) {
+            context.registerReceiverAsUser(this,
+                    UserHandle.ALL,
+                    new IntentFilter(
+                            DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+                    null /* permission */,
+                    null /* scheduler */);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 836a19c..b61ba5c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2806,18 +2806,10 @@
         boolean configChanged;
         boolean surfaceChanged = false;
         boolean animating;
+        boolean hasStatusBarPermission =
+                mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+                        == PackageManager.PERMISSION_GRANTED;
 
-        // if they don't have this permission, mask out the status bar bits
-        int systemUiVisibility = 0;
-        if (attrs != null) {
-            systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility);
-            if ((systemUiVisibility & StatusBarManager.DISABLE_MASK) != 0) {
-                if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
-                        != PackageManager.PERMISSION_GRANTED) {
-                    systemUiVisibility &= ~StatusBarManager.DISABLE_MASK;
-                }
-            }
-        }
         long origId = Binder.clearCallingIdentity();
 
         synchronized(mWindowMap) {
@@ -2832,14 +2824,26 @@
                 win.mRequestedWidth = requestedWidth;
                 win.mRequestedHeight = requestedHeight;
             }
-            if (attrs != null && seq == win.mSeq) {
-                win.mSystemUiVisibility = systemUiVisibility;
-            }
 
             if (attrs != null) {
                 mPolicy.adjustWindowParamsLw(attrs);
             }
 
+            // if they don't have the permission, mask out the status bar bits
+            int systemUiVisibility = 0;
+            if (attrs != null) {
+                systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility);
+                if ((systemUiVisibility & StatusBarManager.DISABLE_MASK) != 0) {
+                    if (!hasStatusBarPermission) {
+                        systemUiVisibility &= ~StatusBarManager.DISABLE_MASK;
+                    }
+                }
+            }
+
+            if (attrs != null && seq == win.mSeq) {
+                win.mSystemUiVisibility = systemUiVisibility;
+            }
+
             winAnimator.mSurfaceDestroyDeferred =
                     (flags&WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY) != 0;
 
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
index 6e03993..1d111a1 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecService.cpp
@@ -142,7 +142,7 @@
     // Handles incoming <Request Active Source> message. If one of logical
     // devices is active, it should reply with <Active Source> message.
     void handleRequestActiveSource();
-    void handleGetOsdName(const cec_message_t& msg);
+    void handleGiveOsdName(const cec_message_t& msg);
     void handleGiveDeviceVendorID(const cec_message_t& msg);
     void handleGetCECVersion(const cec_message_t& msg);
     void handleGetMenuLanguage(const cec_message_t& msg);
@@ -555,8 +555,8 @@
         sendReportPhysicalAddress(msg.destination);
     } else if (opcode == CEC_MESSAGE_REQUEST_ACTIVE_SOURCE) {
         handleRequestActiveSource();
-    } else if (opcode == CEC_MESSAGE_GET_OSD_NAME) {
-        handleGetOsdName(msg);
+    } else if (opcode == CEC_MESSAGE_GIVE_OSD_NAME) {
+        handleGiveOsdName(msg);
     } else if (opcode == CEC_MESSAGE_GIVE_DEVICE_VENDOR_ID) {
         handleGiveDeviceVendorID(msg);
     } else if (opcode == CEC_MESSAGE_GET_CEC_VERSION) {
@@ -631,7 +631,7 @@
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
 
-void HdmiCecHandler::handleGetOsdName(const cec_message_t& msg) {
+void HdmiCecHandler::handleGiveOsdName(const cec_message_t& msg) {
     if (!mOsdName.empty()) {
         sendSetOsdName(msg.destination, msg.initiator, mOsdName.c_str(), mOsdName.length());
     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 1647425..674c6f4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -39,6 +39,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.HashMap;
+import java.util.Set;
 
 /**
  * Stores and restores state for the Device and Profile owners. By definition there can be
@@ -137,6 +138,10 @@
         return profileOwner != null ? profileOwner.name : null;
     }
 
+    Set<Integer> getProfileOwnerKeys() {
+        return mProfileOwners.keySet();
+    }
+
     boolean hasDeviceOwner() {
         return mDeviceOwner != null;
     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1980d1e..e2cd4e2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -19,6 +19,7 @@
 import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
 
 import com.android.internal.R;
+import com.android.internal.app.IAppOpsService;
 import com.android.internal.os.storage.ExternalStorageFormatter;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
@@ -237,6 +238,8 @@
         }
     };
 
+    private IAppOpsService mAppOpsService;
+
     static class ActiveAdmin {
         private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
         private static final String TAG_DISABLE_CAMERA = "disable-camera";
@@ -1209,6 +1212,24 @@
             loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
             loadDeviceOwner();
         }
+        mAppOpsService = IAppOpsService.Stub.asInterface(
+                ServiceManager.getService(Context.APP_OPS_SERVICE));
+        if (mDeviceOwner != null) {
+            if (mDeviceOwner.hasDeviceOwner()) {
+                try {
+                    mAppOpsService.setDeviceOwner(mDeviceOwner.getDeviceOwnerPackageName());
+                } catch (RemoteException e) {
+                    Log.w(LOG_TAG, "Unable to notify AppOpsService of DeviceOwner", e);
+                }
+            }
+            for (Integer i : mDeviceOwner.getProfileOwnerKeys()) {
+                try {
+                    mAppOpsService.setProfileOwner(mDeviceOwner.getProfileOwnerPackageName(i), i);
+                } catch (RemoteException e) {
+                    Log.w(LOG_TAG, "Unable to notify AppOpsService of ProfileOwner", e);
+                }
+            }
+        }
     }
 
     private void handlePasswordExpirationNotification(int userHandle) {
@@ -2953,6 +2974,14 @@
                         "Trying to set device owner but device owner is already set.");
             }
 
+            long token = Binder.clearCallingIdentity();
+            try {
+                mAppOpsService.setDeviceOwner(packageName);
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, "Unable to notify AppOpsService of DeviceOwner", e);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
             if (mDeviceOwner == null) {
                 // Device owner is not set and does not exist, set it.
                 mDeviceOwner = DeviceOwner.createWithDeviceOwner(packageName, ownerName);
@@ -3029,6 +3058,14 @@
                 throw new IllegalStateException(
                         "Trying to set profile owner but user is already set-up.");
             }
+            long token = Binder.clearCallingIdentity();
+            try {
+                mAppOpsService.setProfileOwner(packageName, userHandle);
+            } catch (RemoteException e) {
+                Log.w(LOG_TAG, "Unable to notify AppOpsService of ProfileOwner", e);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
             if (mDeviceOwner == null) {
                 // Device owner state does not exist, create it.
                 mDeviceOwner = DeviceOwner.createWithProfileOwner(packageName, ownerName,
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 8b54264..bcbae60 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -16,6 +16,8 @@
 
 package com.android.server.usb;
 
+import android.alsa.AlsaCardsParser;
+import android.alsa.AlsaDevicesParser;
 import android.content.Context;
 import android.content.Intent;
 import android.hardware.usb.UsbConfiguration;
@@ -29,8 +31,6 @@
 import android.os.UserHandle;
 import android.util.Slog;
 
-import com.android.alsascan.AlsaCardsParser;
-import com.android.alsascan.AlsaDevicesParser;
 import com.android.internal.annotations.GuardedBy;
 
 import java.io.File;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7002744..2bf9ef1 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1773,12 +1773,15 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
      *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+     *
      * @param AID Application id. See ETSI 102.221 and 101.220.
      * @return The logical channel id which is negative on error.
      */
     public int iccOpenLogicalChannel(String AID) {
         try {
-          return getITelephony().iccOpenLogicalChannel(AID);
+            return getITelephony().iccOpenLogicalChannel(AID);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -1790,13 +1793,16 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CCHC command.
      *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+     *
      * @param channel is the channel id to be closed as retruned by a successful
      *            iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
      */
     public boolean iccCloseLogicalChannel(int channel) {
         try {
-          return getITelephony().iccCloseLogicalChannel(channel);
+            return getITelephony().iccCloseLogicalChannel(channel);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -1808,6 +1814,9 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CGLA command.
      *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+     *
      * @param channel is the channel id to be closed as returned by a successful
      *            iccOpenLogicalChannel.
      * @param cla Class of the APDU command.
@@ -1823,8 +1832,30 @@
     public String iccTransmitApduLogicalChannel(int channel, int cla,
             int instruction, int p1, int p2, int p3, String data) {
         try {
-          return getITelephony().iccTransmitApduLogicalChannel(channel, cla,
-                  instruction, p1, p2, p3, data);
+            return getITelephony().iccTransmitApduLogicalChannel(channel, cla,
+                    instruction, p1, p2, p3, data);
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+        return "";
+    }
+
+    /**
+     * Send ENVELOPE to the SIM and return the response.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#SIM_COMMUNICATION SIM_COMMUNICATION}
+     *
+     * @param content String containing SAT/USAT response in hexadecimal
+     *                format starting with command tag. See TS 102 223 for
+     *                details.
+     * @return The APDU response from the ICC card, with the last 4 bytes
+     *         being the status word. If the command fails, returns an empty
+     *         string.
+     */
+    public String sendEnvelopeWithStatus(String content) {
+        try {
+            return getITelephony().sendEnvelopeWithStatus(content);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 72398ad..8b80bfa 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -373,6 +373,18 @@
             int p1, int p2, int p3, String data);
 
     /**
+     * Send ENVELOPE to the SIM and returns the response.
+     *
+     * @param contents  String containing SAT/USAT response in hexadecimal
+     *                  format starting with command tag. See TS 102 223 for
+     *                  details.
+     * @return The APDU response from the ICC card, with the last 4 bytes
+     *         being the status word. If the command fails, returns an empty
+     *         string.
+     */
+    String sendEnvelopeWithStatus(String content);
+
+    /**
      * Read one of the NV items defined in {@link RadioNVItems} / {@code ril_nv_items.h}.
      * Used for device configuration by some CDMA operators.
      *
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 0d9cd18..c162bf28 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -350,7 +350,17 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
     @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+
     public void sendStickyBroadcast(Intent intent) {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 3e9cf43..db802c5 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -216,6 +216,15 @@
         </activity>
 
         <activity
+                android:name="ClipOutlineActivity"
+                android:label="Clip/Outline">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.hwui.TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="DisplayListLayersActivity"
                 android:label="Layers/Display Lists">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
index 1d0a806..e4ea9367 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
@@ -109,26 +109,27 @@
             mToggle = !mToggle;
 
             mRunningAnimations.add(new RenderNodeAnimator(
-                    mX, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 400.0f : 200.0f));
+                    mX, mToggle ? 400.0f : 200.0f));
 
             mRunningAnimations.add(new RenderNodeAnimator(
-                    mY, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 600.0f : 200.0f));
+                    mY, mToggle ? 600.0f : 200.0f));
 
             mRunningAnimations.add(new RenderNodeAnimator(
-                    mRadius, RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 250.0f : 150.0f));
+                    mRadius, mToggle ? 250.0f : 150.0f));
 
             mRunningAnimations.add(new RenderNodeAnimator(
                     mPaint, RenderNodeAnimator.PAINT_ALPHA,
-                    RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 64.0f : 255.0f));
+                    mToggle ? 64.0f : 255.0f));
 
             mRunningAnimations.add(new RenderNodeAnimator(
                     mPaint, RenderNodeAnimator.PAINT_STROKE_WIDTH,
-                    RenderNodeAnimator.DELTA_TYPE_ABSOLUTE, mToggle ? 5.0f : 60.0f));
+                    mToggle ? 5.0f : 60.0f));
 
             TimeInterpolator interp = new OvershootInterpolator(3.0f);
             for (int i = 0; i < mRunningAnimations.size(); i++) {
                 RenderNodeAnimator anim = mRunningAnimations.get(i);
                 anim.setInterpolator(interp);
+                anim.setDuration(1000);
                 anim.start(this);
             }
 
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java
new file mode 100644
index 0000000..af448e8e
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipOutlineActivity.java
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+package com.android.test.hwui;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Outline;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+public class ClipOutlineActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final RegionView group = new RegionView(this);
+
+        final TextView text = new TextView(this);
+        text.setText(buildText());
+        group.addView(text);
+
+        setContentView(group);
+
+        ObjectAnimator animator = ObjectAnimator.ofFloat(group, "clipPosition", 0.0f, 1.0f);
+        animator.setDuration(3000);
+        animator.setRepeatCount(ValueAnimator.INFINITE);
+        animator.setRepeatMode(ValueAnimator.REVERSE);
+        animator.start();
+    }
+
+    private static CharSequence buildText() {
+        StringBuffer buffer = new StringBuffer();
+        for (int i = 0; i < 10; i++) {
+            buffer.append(LOREM_IPSUM);
+        }
+        return buffer;
+    }
+
+    public static class RegionView extends FrameLayout {
+        private float mClipPosition = 0.0f;
+        private Outline mOutline = new Outline();
+        private Rect mRect = new Rect();
+
+        public RegionView(Context c) {
+            super(c);
+            setClipToOutline(true);
+        }
+
+        public float getClipPosition() {
+            return mClipPosition;
+        }
+
+        public void setClipPosition(float clipPosition) {
+            mClipPosition = clipPosition;
+            int w = getWidth() / 2;
+            int h = getHeight() / 2;
+
+            mRect.set(0, 0, w, h);
+            mRect.offset((int) (clipPosition * w), getHeight() / 4);
+            mOutline.setRoundRect(mRect, w / 2);
+            setOutline(mOutline);
+            invalidate();
+        }
+    }
+
+    private static final String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sagittis molestie aliquam. Donec metus metus, laoreet nec sagittis vitae, ultricies sit amet eros. Suspendisse sed massa sit amet felis consectetur gravida. In vitae erat mi, in egestas nisl. Phasellus quis ipsum massa, at scelerisque arcu. Nam lectus est, pellentesque eget lacinia non, congue vitae augue. Aliquam erat volutpat. Pellentesque bibendum tincidunt viverra. Aliquam erat volutpat. Maecenas pretium vulputate placerat. Nulla varius elementum rutrum. Aenean mollis blandit imperdiet. Pellentesque interdum fringilla ligula.";
+}
diff --git a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
index 8f9cf58..b5b12d8 100644
--- a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
+++ b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java
@@ -5,6 +5,7 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
+import android.util.Log;
 import android.view.HardwareRenderer;
 import android.view.RenderNodeAnimator;
 import android.view.View;
@@ -73,14 +74,20 @@
             float delta = (pos - clickedPosition) * 1.1f;
             if (delta == 0) delta = -1;
             RenderNodeAnimator animator = new RenderNodeAnimator(
-                    RenderNodeAnimator.TRANSLATION_Y, RenderNodeAnimator.DELTA_TYPE_DELTA, dy * delta);
+                    RenderNodeAnimator.TRANSLATION_Y, dy * delta);
             animator.setDuration(DURATION);
+            if (child == clickedView) logTranslationY(clickedView);
             animator.start(child);
+            if (child == clickedView) logTranslationY(clickedView);
         }
         //mHandler.postDelayed(mLaunchActivity, (long) (DURATION * .4));
         mLaunchActivity.run();
     }
 
+    private void logTranslationY(View v) {
+        Log.d("RTTest", "View has translationY: " + v.getTranslationY());
+    }
+
     private Runnable mLaunchActivity = new Runnable() {
 
         @Override
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index dca25e5..4e0a9fe 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -453,7 +453,7 @@
     return retStr;
 }
 
-static void printCompatibleScreens(ResXMLTree& tree) {
+static void printCompatibleScreens(ResXMLTree& tree, String8* outError) {
     size_t len;
     ResXMLTree::event_code_t code;
     int depth = 0;
@@ -471,7 +471,12 @@
             continue;
         }
         depth++;
-        String8 tag(tree.getElementName(&len));
+        const char16_t* ctag16 = tree.getElementName(&len);
+        if (ctag16 == NULL) {
+            *outError = "failed to get XML element name (bad string pool)";
+            return;
+        }
+        String8 tag(ctag16);
         if (tag == "screen") {
             int32_t screenSize = getIntegerAttribute(tree,
                     SCREEN_SIZE_ATTR, NULL, -1);
@@ -536,7 +541,12 @@
     while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
         if (code == ResXMLTree::END_TAG) {
             depth--;
-            String8 tag(tree.getElementName(&len));
+            const char16_t* ctag16 = tree.getElementName(&len);
+            if (ctag16 == NULL) {
+                *outError = "failed to get XML element name (bad string pool)";
+                return Vector<String8>();
+            }
+            String8 tag(ctag16);
 
             if (depth == 0 && tag == serviceTagName) {
                 withinApduService = false;
@@ -544,7 +554,12 @@
 
         } else if (code == ResXMLTree::START_TAG) {
             depth++;
-            String8 tag(tree.getElementName(&len));
+            const char16_t* ctag16 = tree.getElementName(&len);
+            if (ctag16 == NULL) {
+                *outError = "failed to get XML element name (bad string pool)";
+                return Vector<String8>();
+            }
+            String8 tag(ctag16);
 
             if (depth == 1) {
                 if (tag == serviceTagName) {
@@ -711,7 +726,12 @@
                     continue;
                 }
                 depth++;
-                String8 tag(tree.getElementName(&len));
+                const char16_t* ctag16 = tree.getElementName(&len);
+                if (ctag16 == NULL) {
+                    fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
+                    goto bail;
+                }
+                String8 tag(ctag16);
                 //printf("Depth %d tag %s\n", depth, tag.string());
                 if (depth == 1) {
                     if (tag != "manifest") {
@@ -970,7 +990,13 @@
                     continue;
                 }
                 depth++;
-                String8 tag(tree.getElementName(&len));
+
+                const char16_t* ctag16 = tree.getElementName(&len);
+                if (ctag16 == NULL) {
+                    fprintf(stderr, "ERROR: failed to get XML element name (bad string pool)\n");
+                    goto bail;
+                }
+                String8 tag(ctag16);
                 //printf("Depth %d,  %s\n", depth, tag.string());
                 if (depth == 1) {
                     if (tag != "manifest") {
@@ -1297,7 +1323,12 @@
                                 goto bail;
                         }
                     } else if (tag == "compatible-screens") {
-                        printCompatibleScreens(tree);
+                        printCompatibleScreens(tree, &error);
+                        if (error != "") {
+                            fprintf(stderr, "ERROR getting compatible screens: %s\n",
+                                    error.string());
+                            goto bail;
+                        }
                         depth--;
                     } else if (tag == "package-verifier") {
                         String8 name = getAttribute(tree, NAME_ATTR, &error);
@@ -1423,7 +1454,7 @@
                                         " service '%s': %s\n", serviceName.string(), error.string());
                             }
                         } else if (bundle->getIncludeMetaData() && tag == "meta-data") {
-                            String8 metaDataName = getAttribute(tree, NAME_ATTR, &error);
+                            String8 metaDataName = getResolvedAttribute(&res, tree, NAME_ATTR, &error);
                             if (error != "") {
                                 fprintf(stderr, "ERROR getting 'android:name' attribute for "
                                         "meta-data:%s\n", error.string());
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index aede236..56c0de9 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -757,7 +757,8 @@
 
     @LayoutlibDelegate
     /*package*/ static void native_drawRoundRect(long nativeCanvas,
-            final RectF rect, final float rx, final float ry, long paint) {
+            final float left, final float top, final float right, final float bottom,
+            final float rx, final float ry, long paint) {
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
                 new GcSnapshot.Drawable() {
@@ -769,16 +770,16 @@
                         if (style == Paint.Style.FILL.nativeInt ||
                                 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
                             graphics.fillRoundRect(
-                                    (int)rect.left, (int)rect.top,
-                                    (int)rect.width(), (int)rect.height(),
+                                    (int)left, (int)top,
+                                    (int)(right - left), (int)(bottom - top),
                                     (int)rx, (int)ry);
                         }
 
                         if (style == Paint.Style.STROKE.nativeInt ||
                                 style == Paint.Style.FILL_AND_STROKE.nativeInt) {
                             graphics.drawRoundRect(
-                                    (int)rect.left, (int)rect.top,
-                                    (int)rect.width(), (int)rect.height(),
+                                    (int)left, (int)top,
+                                    (int)(right - left), (int)(bottom - top),
                                     (int)rx, (int)ry);
                         }
                     }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 25eaaf5..83df745 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -420,7 +420,7 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
+    /*package*/ static void native_setShadowLayer(long paint, float radius, float dx, float dy,
             int color) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -428,6 +428,14 @@
     }
 
     @LayoutlibDelegate
+    /*package*/ static boolean native_hasShadowLayer(long paint) {
+        // FIXME
+        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+                "Paint.hasShadowLayer is not supported.", null, null /*data*/);
+        return false;
+    }
+
+    @LayoutlibDelegate
     /*package*/ static boolean isElegantTextHeight(Paint thisPaint) {
         return false;
     }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index b235408..0ec7115 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -318,16 +318,6 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addRect(long nPath, RectF rect, int dir) {
-        Path_Delegate pathDelegate = sManager.getDelegate(nPath);
-        if (pathDelegate == null) {
-            return;
-        }
-
-        pathDelegate.addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
-    }
-
-    @LayoutlibDelegate
     /*package*/ static void native_addRect(long nPath,
             float left, float top, float right, float bottom, int dir) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
@@ -339,14 +329,15 @@
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_addOval(long nPath, RectF oval, int dir) {
+    /*package*/ static void native_addOval(long nPath, float left, float top, float right,
+            float bottom, int dir) {
         Path_Delegate pathDelegate = sManager.getDelegate(nPath);
         if (pathDelegate == null) {
             return;
         }
 
         pathDelegate.mPath.append(new Ellipse2D.Float(
-                oval.left, oval.top, oval.width(), oval.height()), false);
+                left, top, right - left, bottom - top), false);
     }
 
     @LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/os/Build_Delegate.java b/tools/layoutlib/bridge/src/android/os/SystemProperties_Delegate.java
similarity index 69%
rename from tools/layoutlib/bridge/src/android/os/Build_Delegate.java
rename to tools/layoutlib/bridge/src/android/os/SystemProperties_Delegate.java
index ff82a5e..1e7564e 100644
--- a/tools/layoutlib/bridge/src/android/os/Build_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/os/SystemProperties_Delegate.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * 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.
@@ -23,26 +23,29 @@
 import java.util.Map;
 
 /**
- * Delegate implementing the native methods of android.os.Build
+ * Delegate implementing the native methods of android.os.SystemProperties
  *
- * Through the layoutlib_create tool, the original native methods of Build have been replaced
- * by calls to methods of the same name in this delegate class.
+ * Through the layoutlib_create tool, the original native methods of SystemProperties have been
+ * replaced by calls to methods of the same name in this delegate class.
  *
  * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
  * around to map int to instance of the delegate.
- *
  */
-public class Build_Delegate {
+public class SystemProperties_Delegate {
 
     @LayoutlibDelegate
-    /*package*/ static String getString(String property) {
+    /*package*/ static String native_get(String key) {
+        return native_get(key, "");
+    }
+
+    @LayoutlibDelegate
+    /*package*/ static String native_get(String key, String def) {
         Map<String, String> properties = Bridge.getPlatformProperties();
-        String value = properties.get(property);
+        String value = properties.get(key);
         if (value != null) {
             return value;
         }
 
-        return Build.UNKNOWN;
+        return def;
     }
-
 }
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 08e9d99..d31239b 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
@@ -567,7 +567,7 @@
         StyleResourceValue customStyleValues = null;
         if (customStyle != null) {
             ResourceValue item = mRenderResources.findResValue(customStyle,
-                    false /*forceFrameworkOnly*/);
+                    isPlatformFile /*forceFrameworkOnly*/);
 
             // resolve it in case it links to something else
             item = mRenderResources.resolveResValue(item);
@@ -1284,6 +1284,14 @@
     }
 
     @Override
+    public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
+            String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
+            Handler scheduler,
+            int initialCode, String initialData, Bundle initialExtras) {
+        // pass
+    }
+
+    @Override
     public void sendStickyBroadcast(Intent arg0) {
         // pass
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 59979ce..bb72a1e 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -133,7 +133,6 @@
         "android.graphics.BitmapFactory#finishDecode",
         "android.os.Handler#sendMessageAtTime",
         "android.os.HandlerThread#run",
-        "android.os.Build#getString",
         "android.text.format.DateFormat#is24HourFormat",
         "android.view.Choreographer#getRefreshRate",
         "android.view.Display#updateDisplayInfoLocked",
@@ -148,6 +147,7 @@
         "com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
         "com.android.internal.util.XmlUtils#convertValueToInt",
         "com.android.internal.textservice.ITextServicesManager$Stub#asInterface",
+        "android.os.SystemProperties#native_get",
     };
 
     /**
diff --git a/tools/layoutlib/rename_font/README b/tools/layoutlib/rename_font/README
new file mode 100644
index 0000000..600b756
--- /dev/null
+++ b/tools/layoutlib/rename_font/README
@@ -0,0 +1,9 @@
+This tool is used to rename the PS name encoded inside the ttf font that we ship
+with the SDK. There is bug in Java that returns incorrect results for
+java.awt.Font#layoutGlyphVector() if two fonts with same name but differnt
+versions are loaded. As a workaround, we rename all the fonts that we ship with
+the SDK by appending the font version to its name.
+
+
+The build_font.py copies all files from input_dir to output_dir while renaming
+the font files (*.ttf) in the process.
diff --git a/tools/layoutlib/rename_font/Roboto-Regular.ttf b/tools/layoutlib/rename_font/Roboto-Regular.ttf
new file mode 100644
index 0000000..7469063
--- /dev/null
+++ b/tools/layoutlib/rename_font/Roboto-Regular.ttf
Binary files differ
diff --git a/tools/layoutlib/rename_font/build_font.py b/tools/layoutlib/rename_font/build_font.py
new file mode 100755
index 0000000..ea3dccc
--- /dev/null
+++ b/tools/layoutlib/rename_font/build_font.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+
+# 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.
+
+"""
+Rename the PS name of all fonts in the input directory and copy them to the
+output directory.
+
+Usage: build_font.py /path/to/input_fonts/ /path/to/output_fonts/
+
+"""
+
+import sys
+# fontTools is available at platform/external/fonttools
+from fontTools import ttx
+import re
+import os
+from lxml import etree
+import shutil
+import glob
+
+def main(argv):
+  if len(argv) != 2:
+    print "Usage: build_font.py /path/to/input_fonts/ /path/to/out/dir/"
+    sys.exit(1)
+  if not os.path.isdir(argv[0]):
+    print argv[0] + "is not a valid directory"
+    sys.exit(1)
+  if not os.path.isdir(argv[1]):
+    print argv[1] + "is not a valid directory"
+    sys.exit(1)
+  cwd = os.getcwd()
+  os.chdir(argv[1])
+  files = glob.glob('*')
+  for filename in files:
+    os.remove(filename)
+  os.chdir(cwd)
+  for filename in os.listdir(argv[0]):
+    if not os.path.splitext(filename)[1].lower() == ".ttf":
+      shutil.copy(os.path.join(argv[0], filename), argv[1])
+      continue
+    print os.path.join(argv[0], filename)
+    old_ttf_path = os.path.join(argv[0], filename)
+    # run ttx to generate an xml file in the output folder which represents all
+    # its info
+    ttx_args = ["-d", argv[1], old_ttf_path]
+    ttx.main(ttx_args)
+    # the path to the output file. The file name is the fontfilename.ttx
+    ttx_path = os.path.join(argv[1], filename)
+    ttx_path = ttx_path[:-1] + "x"
+    # now parse the xml file to change its PS name.
+    tree = etree.parse(ttx_path)
+    encoding = tree.docinfo.encoding
+    root = tree.getroot()
+    for name in root.iter('name'):
+      [old_ps_name, version] = get_font_info(name)
+      new_ps_name = old_ps_name + version
+      update_name(name, new_ps_name)
+    tree.write(ttx_path, xml_declaration=True, encoding=encoding )
+    # generate the udpated font now.
+    ttx_args = ["-d", argv[1], ttx_path]
+    ttx.main(ttx_args)
+    # delete the temp ttx file.
+    os.remove(ttx_path)
+
+def get_font_info(tag):
+  ps_name = None
+  ps_version = None
+  for namerecord in tag.iter('namerecord'):
+    if 'nameID' in namerecord.attrib:
+      # if the tag has nameID=6, it is the postscript name of the font.
+      # see: http://scripts.sil.org/cms/scripts/page.php?item_id=IWS-Chapter08#3054f18b
+      if namerecord.attrib['nameID'] == '6':
+        if ps_name is not None:
+          if not sanitize(namerecord.text) == ps_name:
+            sys.exit('found multiple possibilities of the font name')
+        else:
+          ps_name = sanitize(namerecord.text)
+      # nameID=5 means the font version
+      if namerecord.attrib['nameID'] == '5':
+        if ps_version is not None:
+          if not ps_version == get_version(namerecord.text):
+            sys.exit('found multiple possibilities of the font version')
+        else:
+          ps_version = get_version(namerecord.text)
+  if ps_name is not None and ps_version is not None:
+    return [ps_name, ps_version]
+  sys.exit('didn\'t find the font name or version')
+
+
+def update_name(tag, name):
+  for namerecord in tag.iter('namerecord'):
+    if 'nameID' in namerecord.attrib:
+      if namerecord.attrib['nameID'] == '6':
+        namerecord.text = name
+
+def sanitize(string):
+  return re.sub(r'[^\w-]+', '', string)
+
+def get_version(string):
+  # The string must begin with "Version n.nn "
+  # to extract n.nn, we return the second entry in the split strings.
+  string = string.strip()
+  if not string.startswith("Version "):
+    sys.exit('mal-formed font version')
+  return sanitize(string.split()[1])
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
diff --git a/tools/layoutlib/rename_font/test.py b/tools/layoutlib/rename_font/test.py
new file mode 100755
index 0000000..d4c86cb
--- /dev/null
+++ b/tools/layoutlib/rename_font/test.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+"""Tests build_font.py by renaming a font.
+
+The test copies Roboto-Regular.ttf to a tmp directory and ask build_font.py to rename it and put in another dir.
+We then use ttx to dump the new font to its xml and check if rename was successful
+
+To test locally, use:
+PYTHONPATH="$PYTHONPATH:/path/to/android/checkout/external/fonttools/Lib" ./test.py
+"""
+
+import unittest
+import build_font
+
+from fontTools import ttx
+import os
+from lxml import etree
+import shutil
+import tempfile
+
+class MyTest(unittest.TestCase):
+  def test(self):
+    font_name = "Roboto-Regular.ttf"
+    srcdir = tempfile.mkdtemp()
+    print "srcdir: " + srcdir
+    shutil.copy(font_name, srcdir)
+    destdir = tempfile.mkdtemp()
+    print "destdir: " + destdir
+    self.assertTrue(build_font.main([srcdir, destdir]) is None)
+    out_path = os.path.join(destdir, font_name)
+    ttx.main([out_path])
+    ttx_path = out_path[:-1] + "x"
+    tree = etree.parse(ttx_path)
+    root = tree.getroot()
+    name_tag = root.find('name')
+    [f_name, f_version] = build_font.get_font_info(name_tag)
+    shutil.rmtree(srcdir)
+    shutil.rmtree(destdir)
+    self.assertEqual(f_name, "Roboto-Regular1200310")
+
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 85b81d9..e73cce1b 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -417,6 +417,12 @@
     public int autoJoinStatus;
 
     /**
+     * Set if the configuration was self added by the framework
+     * @hide
+     */
+    public boolean selfAdded;
+
+    /**
      * @hide
      * Indicate that a WifiConfiguration is temporary and should not be saved
      * nor considered by AutoJoin.
@@ -498,6 +504,8 @@
         proxySettings = ProxySettings.UNASSIGNED;
         linkProperties = new LinkProperties();
         autoJoinStatus = AUTO_JOIN_ENABLED;
+        selfAdded = false;
+        ephemeral = false;
     }
 
     /**
@@ -794,8 +802,28 @@
         return configKey(false);
     }
 
+    /** @hide
+     * return the config key string based on a scan result
+     */
+    static public String configKey(ScanResult result) {
+        String key = "\"" + result.SSID + "\"";
 
-        /** Implement the Parcelable interface {@hide} */
+        if (result.capabilities.contains("WEP")) {
+            key = key + "-WEP";
+        }
+
+        if (result.capabilities.contains("PSK")) {
+            key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK];
+        }
+
+        if (result.capabilities.contains("EAP")) {
+            key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+        }
+
+        return key;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
     public int describeContents() {
         return 0;
     }
@@ -849,6 +877,7 @@
             }
             mCachedConfigKey = null; //force null configKey
             autoJoinStatus = source.autoJoinStatus;
+            selfAdded = source.selfAdded;
 
             if (source.visibility != null) {
                 visibility = new Visibility(source.visibility);
@@ -886,6 +915,7 @@
         dest.writeString(dhcpServer);
         dest.writeString(defaultGwMacAddress);
         dest.writeInt(autoJoinStatus);
+        dest.writeInt(selfAdded ? 1 : 0);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -920,7 +950,7 @@
                 config.dhcpServer = in.readString();
                 config.defaultGwMacAddress = in.readString();
                 config.autoJoinStatus = in.readInt();
-
+                config.selfAdded = in.readInt() != 0;
                 return config;
             }