Merge "Initial changes to enable keyboard support with alternate Recents. (Bug 14067913)"
diff --git a/Android.mk b/Android.mk
index 89b2884..9828ea6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -147,6 +147,8 @@
 	core/java/android/hardware/display/IDisplayManagerCallback.aidl \
 	core/java/android/hardware/hdmi/IHdmiCecListener.aidl \
 	core/java/android/hardware/hdmi/IHdmiCecService.aidl \
+	core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
+	core/java/android/hardware/hdmi/IHdmiControlService.aidl \
 	core/java/android/hardware/input/IInputManager.aidl \
 	core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
 	core/java/android/hardware/location/IFusedLocationHardware.aidl \
@@ -324,7 +326,6 @@
 	telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
 	telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
-	telephony/java/com/android/internal/telephony/ITelephonyListener.aidl \
 	telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl \
 	telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl \
 	telephony/java/com/android/internal/telephony/IThirdPartyCallSendDtmfCallback.aidl \
@@ -333,7 +334,7 @@
 	telephony/java/com/android/internal/telephony/ISms.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
 	wifi/java/android/net/wifi/IWifiManager.aidl \
-	wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl \
+	wifi/java/android/net/wifi/passpoint/IPasspointManager.aidl \
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
 	wifi/java/android/net/wifi/IWifiScanner.aidl \
 	packages/services/PacProcessor/com/android/net/IProxyService.aidl \
diff --git a/api/current.txt b/api/current.txt
index f8b6f59..20e82d1 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);
@@ -3352,12 +3348,12 @@
     method public final void setProgressBarIndeterminate(boolean);
     method public final void setProgressBarIndeterminateVisibility(boolean);
     method public final void setProgressBarVisibility(boolean);
-    method public void setRecentsActivityValues(android.app.ActivityManager.RecentsActivityValues);
     method public void setRequestedOrientation(int);
     method public final void setResult(int);
     method public final void setResult(int, android.content.Intent);
     method public final void setSecondaryProgress(int);
     method public void setSharedElementListener(android.app.SharedElementListener);
+    method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
     method public void setTitle(java.lang.CharSequence);
     method public void setTitle(int);
     method public deprecated void setTitleColor(int);
@@ -3482,7 +3478,6 @@
     method public void readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
-    field public android.app.ActivityManager.RecentsActivityValues activityValues;
     field public android.content.Intent baseIntent;
     field public java.lang.CharSequence description;
     field public int id;
@@ -3490,21 +3485,6 @@
     field public int persistentId;
   }
 
-  public static class ActivityManager.RecentsActivityValues implements android.os.Parcelable {
-    ctor public ActivityManager.RecentsActivityValues(android.app.ActivityManager.RecentsActivityValues);
-    ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence, android.graphics.Bitmap, int);
-    ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence, android.graphics.Bitmap);
-    ctor public ActivityManager.RecentsActivityValues(java.lang.CharSequence);
-    ctor public ActivityManager.RecentsActivityValues();
-    method public int describeContents();
-    method public void readFromParcel(android.os.Parcel);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-    field public int colorPrimary;
-    field public android.graphics.Bitmap icon;
-    field public java.lang.CharSequence label;
-  }
-
   public static class ActivityManager.RunningAppProcessInfo implements android.os.Parcelable {
     ctor public ActivityManager.RunningAppProcessInfo();
     ctor public ActivityManager.RunningAppProcessInfo(java.lang.String, int, java.lang.String[]);
@@ -3574,6 +3554,21 @@
     field public android.content.ComponentName topActivity;
   }
 
+  public static class ActivityManager.TaskDescription implements android.os.Parcelable {
+    ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap, int);
+    ctor public ActivityManager.TaskDescription(java.lang.String, android.graphics.Bitmap);
+    ctor public ActivityManager.TaskDescription(java.lang.String);
+    ctor public ActivityManager.TaskDescription();
+    ctor public ActivityManager.TaskDescription(android.app.ActivityManager.TaskDescription);
+    method public int describeContents();
+    method public android.graphics.Bitmap getIcon();
+    method public java.lang.String getLabel();
+    method public int getPrimaryColor();
+    method public void readFromParcel(android.os.Parcel);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public class ActivityOptions {
     method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
     method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
@@ -4102,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);
@@ -4516,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;
@@ -4523,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);
@@ -4543,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();
@@ -4903,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();
@@ -5236,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";
@@ -6649,6 +6630,7 @@
     field public static final java.lang.String DROPBOX_SERVICE = "dropbox";
     field public static final java.lang.String FINGERPRINT_SERVICE = "fingerprint";
     field public static final java.lang.String HDMI_CEC_SERVICE = "hdmi_cec";
+    field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
     field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
     field public static final java.lang.String INPUT_SERVICE = "input";
     field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
@@ -6679,8 +6661,8 @@
     field public static final java.lang.String USER_SERVICE = "user";
     field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
     field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
-    field public static final java.lang.String WIFI_HOTSPOT_SERVICE = "wifihotspot";
     field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
+    field public static final java.lang.String WIFI_PASSPOINT_SERVICE = "wifipasspoint";
     field public static final java.lang.String WIFI_SERVICE = "wifi";
     field public static final java.lang.String WINDOW_SERVICE = "window";
   }
@@ -7123,7 +7105,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";
@@ -10089,7 +10070,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);
@@ -10117,6 +10098,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[]);
@@ -10214,7 +10196,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);
@@ -10248,7 +10232,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();
@@ -10299,7 +10283,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);
@@ -10608,7 +10592,7 @@
     ctor public RadialGradient(float, float, float, int, int, android.graphics.Shader.TileMode);
   }
 
-  public class Rasterizer {
+  public deprecated class Rasterizer {
     ctor public Rasterizer();
   }
 
@@ -11356,6 +11340,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 {
@@ -12278,12 +12280,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 {
@@ -12303,7 +12309,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;
   }
@@ -12312,7 +12318,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();
@@ -12323,12 +12329,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);
@@ -12344,10 +12344,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 {
@@ -12364,23 +12371,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 {
@@ -12456,16 +12446,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
@@ -12473,10 +12464,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
@@ -12494,6 +12489,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
@@ -12508,9 +12504,15 @@
     field public static final int MESSAGE_VENDOR_REMOTE_BUTTON_UP = 139; // 0x8b
     field public static final int POWER_STATUS_ON = 0; // 0x0
     field public static final int POWER_STATUS_STANDBY = 1; // 0x1
+    field public static final int POWER_STATUS_TRANSIENT_TO_ON = 2; // 0x2
+    field public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3; // 0x3
     field public static final int POWER_STATUS_UNKNOWN = -1; // 0xffffffff
-    field public static final int POWER_TRANSIENT_TO_ON = 2; // 0x2
-    field public static final int POWER_TRANSIENT_TO_STANDBY = 3; // 0x3
+    field public static final int RESULT_ALREADY_IN_PROGRESS = 4; // 0x4
+    field public static final int RESULT_EXCEPTION = 5; // 0x5
+    field public static final int RESULT_SOURCE_NOT_AVAILABLE = 2; // 0x2
+    field public static final int RESULT_SUCCESS = 0; // 0x0
+    field public static final int RESULT_TARGET_NOT_AVAILABLE = 3; // 0x3
+    field public static final int RESULT_TIMEOUT = 1; // 0x1
     field public static final int UNKNOWN_VENDOR_ID = 16777215; // 0xffffff
   }
 
@@ -12556,6 +12558,27 @@
     field public static final byte[] EMPTY_PARAM;
   }
 
+  public final class HdmiControlManager {
+    method public android.hardware.hdmi.HdmiPlaybackClient getPlaybackClient();
+    method public android.hardware.hdmi.HdmiTvClient getTvClient();
+  }
+
+  public final class HdmiPlaybackClient {
+    method public void oneTouchPlay(android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback);
+    method public void queryDisplayStatus(android.hardware.hdmi.HdmiPlaybackClient.DisplayStatusCallback);
+  }
+
+  public static abstract interface HdmiPlaybackClient.DisplayStatusCallback {
+    method public abstract void onComplete(int);
+  }
+
+  public static abstract interface HdmiPlaybackClient.OneTouchPlayCallback {
+    method public abstract void onComplete(int);
+  }
+
+  public final class HdmiTvClient {
+  }
+
 }
 
 package android.hardware.input {
@@ -13712,16 +13735,17 @@
     ctor public DeniedByServerException(java.lang.String);
   }
 
-  public final class DngCreator {
+  public final class DngCreator implements java.lang.AutoCloseable {
     ctor public DngCreator(android.hardware.camera2.CameraCharacteristics, android.hardware.camera2.CaptureResult);
+    method public void close();
     method public android.media.DngCreator setDescription(java.lang.String);
     method public android.media.DngCreator setLocation(android.location.Location);
     method public android.media.DngCreator setOrientation(int);
     method public android.media.DngCreator setThumbnail(android.graphics.Bitmap);
     method public android.media.DngCreator setThumbnail(android.media.Image);
-    method public void writeByteBuffer(java.io.OutputStream, java.nio.ByteBuffer, int, long) throws java.io.IOException;
+    method public void writeByteBuffer(java.io.OutputStream, android.util.Size, java.nio.ByteBuffer, long) throws java.io.IOException;
     method public void writeImage(java.io.OutputStream, android.media.Image) throws java.io.IOException;
-    method public void writeInputStream(java.io.OutputStream, java.io.InputStream, int, long) throws java.io.IOException;
+    method public void writeInputStream(java.io.OutputStream, android.util.Size, java.io.InputStream, long) throws java.io.IOException;
   }
 
   public class ExifInterface {
@@ -15547,7 +15571,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();
@@ -15557,6 +15581,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
   }
@@ -15846,6 +15875,16 @@
     field public int serverAddress;
   }
 
+  public class LinkAddress implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.net.InetAddress getAddress();
+    method public int getFlags();
+    method public int getNetworkPrefixLength();
+    method public int getScope();
+    method public boolean isSameAddressAs(android.net.LinkAddress);
+    method public void writeToParcel(android.os.Parcel, int);
+  }
+
   public class LocalServerSocket {
     ctor public LocalServerSocket(java.lang.String) throws java.io.IOException;
     ctor public LocalServerSocket(java.io.FileDescriptor) throws java.io.IOException;
@@ -15914,6 +15953,44 @@
     field public static final java.lang.String MAILTO_SCHEME = "mailto:";
   }
 
+  public final class NetworkCapabilities implements android.os.Parcelable {
+    ctor public NetworkCapabilities();
+    ctor public NetworkCapabilities(android.net.NetworkCapabilities);
+    method public void addNetworkCapability(int);
+    method public void addTransportType(int);
+    method public int describeContents();
+    method public int getLinkDownstreamBandwidthKbps();
+    method public int getLinkUpstreamBandwidthKbps();
+    method public java.util.Collection<java.lang.Integer> getNetworkCapabilities();
+    method public java.util.Collection<java.lang.Integer> getTransportTypes();
+    method public boolean hasCapability(int);
+    method public boolean hasTransport(int);
+    method public void removeNetworkCapability(int);
+    method public void removeTransportType(int);
+    method public void setLinkDownstreamBandwidthKbps(int);
+    method public void setLinkUpstreamBandwidthKbps(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int NET_CAPABILITY_CBS = 5; // 0x5
+    field public static final int NET_CAPABILITY_DUN = 2; // 0x2
+    field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
+    field public static final int NET_CAPABILITY_FOTA = 3; // 0x3
+    field public static final int NET_CAPABILITY_IA = 7; // 0x7
+    field public static final int NET_CAPABILITY_IMS = 4; // 0x4
+    field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc
+    field public static final int NET_CAPABILITY_MMS = 0; // 0x0
+    field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
+    field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+    field public static final int NET_CAPABILITY_RCS = 8; // 0x8
+    field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
+    field public static final int NET_CAPABILITY_WIFI_P2P = 6; // 0x6
+    field public static final int NET_CAPABILITY_XCAP = 9; // 0x9
+    field public static final int TRANSPORT_BLUETOOTH = 2; // 0x2
+    field public static final int TRANSPORT_CELLULAR = 0; // 0x0
+    field public static final int TRANSPORT_ETHERNET = 3; // 0x3
+    field public static final int TRANSPORT_WIFI = 1; // 0x1
+  }
+
   public class NetworkInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.net.NetworkInfo.DetailedState getDetailedState();
@@ -15987,6 +16064,20 @@
     method public void writeToParcel(android.os.Parcel, int);
   }
 
+  public class RouteInfo implements android.os.Parcelable {
+    ctor public RouteInfo(android.net.LinkAddress, java.net.InetAddress, java.lang.String);
+    ctor public RouteInfo(android.net.LinkAddress, java.net.InetAddress);
+    ctor public RouteInfo(java.net.InetAddress);
+    ctor public RouteInfo(android.net.LinkAddress);
+    method public int describeContents();
+    method public android.net.LinkAddress getDestination();
+    method public java.net.InetAddress getGateway();
+    method public java.lang.String getInterface();
+    method public boolean isDefaultRoute();
+    method public boolean matches(java.net.InetAddress);
+    method public void writeToParcel(android.os.Parcel, int);
+  }
+
   public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
     ctor public deprecated SSLCertificateSocketFactory(int);
     method public java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException;
@@ -16823,6 +16914,86 @@
     method public void setWorkSource(android.os.WorkSource);
   }
 
+  public class WifiScanner {
+    method public void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.HotspotInfo[]);
+    method public void resetHotlist(android.net.wifi.WifiScanner.HotlistListener);
+    method public void retrieveScanResults(boolean, android.net.wifi.WifiScanner.ScanListener);
+    method public void setHotlist(android.net.wifi.WifiScanner.HotspotInfo[], int, android.net.wifi.WifiScanner.HotlistListener);
+    method public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
+    method public void startTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
+    method public void stopBackgroundScan(android.net.wifi.WifiScanner.ScanListener);
+    method public void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
+    field public static final int MAX_SCAN_PERIOD_MS = 1024000; // 0xfa000
+    field public static final int MIN_SCAN_PERIOD_MS = 2000; // 0x7d0
+    field public static final int REASON_CONFLICTING_REQUEST = -4; // 0xfffffffc
+    field public static final int REASON_INVALID_LISTENER = -2; // 0xfffffffe
+    field public static final int REASON_INVALID_REQUEST = -3; // 0xfffffffd
+    field public static final int REASON_SUCCEEDED = 0; // 0x0
+    field public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
+    field public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0; // 0x0
+    field public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1; // 0x1
+    field public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2; // 0x2
+    field public static final int WIFI_BAND_24_GHZ = 1; // 0x1
+    field public static final int WIFI_BAND_5_GHZ = 2; // 0x2
+    field public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; // 0x4
+    field public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6; // 0x6
+    field public static final int WIFI_BAND_BOTH = 3; // 0x3
+    field public static final int WIFI_BAND_BOTH_WITH_DFS = 7; // 0x7
+    field public static final int WIFI_BAND_UNSPECIFIED = 0; // 0x0
+  }
+
+  public static class WifiScanner.ChannelSpec {
+    ctor public WifiScanner.ChannelSpec(int);
+    field public int frequency;
+  }
+
+  public static class WifiScanner.FullScanResult implements android.os.Parcelable {
+    ctor public WifiScanner.FullScanResult();
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public android.net.wifi.WifiScanner.InformationElement[] informationElements;
+    field public android.net.wifi.ScanResult result;
+  }
+
+  public static abstract interface WifiScanner.HotlistListener {
+    method public abstract void onFound(android.net.wifi.ScanResult[]);
+  }
+
+  public static class WifiScanner.HotspotInfo {
+    ctor public WifiScanner.HotspotInfo();
+    field public java.lang.String bssid;
+    field public int frequencyHint;
+    field public int high;
+    field public int low;
+  }
+
+  public static class WifiScanner.InformationElement {
+    ctor public WifiScanner.InformationElement();
+    field public byte[] bytes;
+    field public int id;
+  }
+
+  public static abstract interface WifiScanner.ScanListener {
+    method public abstract void onFullResult(android.net.wifi.WifiScanner.FullScanResult);
+    method public abstract void onPeriodChanged(int);
+    method public abstract void onResults(android.net.wifi.ScanResult[]);
+  }
+
+  public static class WifiScanner.ScanSettings implements android.os.Parcelable {
+    ctor public WifiScanner.ScanSettings();
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public int band;
+    field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
+    field public int periodInMs;
+    field public int reportEvents;
+  }
+
+  public static abstract interface WifiScanner.WifiChangeListener {
+    method public abstract void onChanging(android.net.wifi.ScanResult[]);
+    method public abstract void onQuiescence(android.net.wifi.ScanResult[]);
+  }
+
   public class WpsInfo implements android.os.Parcelable {
     ctor public WpsInfo();
     ctor public WpsInfo(android.net.wifi.WpsInfo);
@@ -16840,19 +17011,6 @@
 
 }
 
-package android.net.wifi.hotspot {
-
-  public abstract interface IWifiHotspotManager implements android.os.IInterface {
-    method public abstract void test() throws android.os.RemoteException;
-  }
-
-  public class WifiHotspotManager {
-    ctor public WifiHotspotManager(android.content.Context, android.net.wifi.hotspot.IWifiHotspotManager);
-    method public void test();
-  }
-
-}
-
 package android.net.wifi.p2p {
 
   public class WifiP2pConfig implements android.os.Parcelable {
@@ -17048,6 +17206,114 @@
 
 }
 
+package android.net.wifi.passpoint {
+
+  public abstract interface IPasspointManager implements android.os.IInterface {
+    method public abstract android.os.Messenger getMessenger() throws android.os.RemoteException;
+    method public abstract int getPasspointState() throws android.os.RemoteException;
+  }
+
+  public class PasspointCredential implements android.os.Parcelable {
+    ctor public PasspointCredential();
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+  }
+
+  public class PasspointInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ANQP_CAPABILITY = 1; // 0x1
+    field public static final int CELLULAR_NETWORK = 64; // 0x40
+    field public static final int CONNECTION_CAPABILITY = 2048; // 0x800
+    field public static final int DOMAIN_NAME = 128; // 0x80
+    field public static final int HOTSPOT_CAPABILITY = 256; // 0x100
+    field public static final int IP_ADDR_TYPE_AVAILABILITY = 16; // 0x10
+    field public static final int NAI_REALM = 32; // 0x20
+    field public static final int NETWORK_AUTH_TYPE = 4; // 0x4
+    field public static final int OPERATOR_FRIENDLY_NAME = 512; // 0x200
+    field public static final int OSU_PROVIDER = 4096; // 0x1000
+    field public static final int PRESET_ALL = 8191; // 0x1fff
+    field public static final int PRESET_CRED_MATCH = 481; // 0x1e1
+    field public static final int ROAMING_CONSORTIUM = 8; // 0x8
+    field public static final int VENUE_NAME = 2; // 0x2
+    field public static final int WAN_METRICS = 1024; // 0x400
+    field public java.lang.String bssid;
+    field public java.lang.String cellularNetwork;
+    field public java.lang.String connectionCapability;
+    field public java.lang.String domainName;
+    field public java.lang.String ipAddrTypeAvaibility;
+    field public java.lang.String naiRealm;
+    field public java.lang.String networkAuthType;
+    field public java.lang.String operatorFriendlyName;
+    field public java.util.List osuProviderList;
+    field public java.lang.String roamingConsortium;
+    field public java.lang.String venueName;
+    field public java.lang.String wanMetrics;
+  }
+
+  public class PasspointManager {
+    ctor public PasspointManager(android.content.Context, android.net.wifi.passpoint.IPasspointManager);
+    method public boolean addCredential(android.net.wifi.passpoint.PasspointCredential);
+    method public void connect(android.net.wifi.passpoint.PasspointPolicy);
+    method public int getPasspointState();
+    method public java.util.List<android.net.wifi.passpoint.PasspointCredential> getSavedCredentials();
+    method public android.net.wifi.passpoint.PasspointManager.Channel initialize(android.content.Context, android.os.Looper, android.net.wifi.passpoint.PasspointManager.ChannelListener);
+    method public boolean removeCredential(android.net.wifi.passpoint.PasspointCredential);
+    method public java.util.List<android.net.wifi.passpoint.PasspointPolicy> requestCredentialMatch(java.util.List<android.net.wifi.ScanResult>);
+    method public void requestOsuIcons(android.net.wifi.passpoint.PasspointManager.Channel, java.util.List<android.net.wifi.passpoint.PasspointOsuProvider>, int, android.net.wifi.passpoint.PasspointManager.ActionListener);
+    method public boolean updateCredential(android.net.wifi.passpoint.PasspointCredential);
+    field public static final int BUSY = 2; // 0x2
+    field public static final int ERROR = 0; // 0x0
+    field public static final java.lang.String PASSPOINT_CRED_CHANGED_ACTION = "android.net.wifi.passpoint.CRED_CHANGE";
+    field public static final int PASSPOINT_STATE_ACCESS = 3; // 0x3
+    field public static final java.lang.String PASSPOINT_STATE_CHANGED_ACTION = "android.net.wifi.passpoint.STATE_CHANGE";
+    field public static final int PASSPOINT_STATE_DISABLED = 1; // 0x1
+    field public static final int PASSPOINT_STATE_DISCOVERY = 2; // 0x2
+    field public static final int PASSPOINT_STATE_PROVISION = 4; // 0x4
+    field public static final int PASSPOINT_STATE_UNKNOWN = 0; // 0x0
+    field public static final int WIFI_DISABLED = 1; // 0x1
+  }
+
+  public static abstract interface PasspointManager.ActionListener {
+    method public abstract void onFailure(int);
+    method public abstract void onSuccess();
+  }
+
+  public static class PasspointManager.Channel {
+  }
+
+  public static abstract interface PasspointManager.ChannelListener {
+    method public abstract void onChannelDisconnected();
+  }
+
+  public class PasspointOsuProvider implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int OSU_METHOD_OMADM = 0; // 0x0
+    field public static final int OSU_METHOD_SOAP = 1; // 0x1
+    field public static final int OSU_METHOD_UNKNOWN = -1; // 0xffffffff
+    field public java.lang.String friendlyName;
+    field public java.lang.Object icon;
+    field public java.lang.String iconFileName;
+    field public int iconHeight;
+    field public java.lang.String iconType;
+    field public int iconWidth;
+    field public int osuMethod;
+    field public java.lang.String osuNai;
+    field public java.lang.String osuService;
+    field public java.lang.String serverUri;
+    field public java.lang.String ssid;
+  }
+
+  public class PasspointPolicy implements android.os.Parcelable {
+    ctor public PasspointPolicy();
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+  }
+
+}
+
 package android.nfc {
 
   public class FormatException extends java.lang.Exception {
@@ -19553,6 +19819,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
@@ -19560,6 +19827,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 {
@@ -25294,82 +25562,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 {
@@ -26574,6 +26776,83 @@
     enum_constant public static final android.telecomm.CallState RINGING;
   }
 
+  public abstract class Connection {
+    ctor protected Connection();
+    method public final android.telecomm.CallAudioState getCallAudioState();
+    method public final android.net.Uri getHandle();
+    method protected void onAbort();
+    method protected void onAnswer();
+    method protected void onDisconnect();
+    method protected void onHold();
+    method protected void onPlayDtmfTone(char);
+    method protected void onReject();
+    method protected void onSetAudioState(android.telecomm.CallAudioState);
+    method protected void onSetSignal(android.os.Bundle);
+    method protected void onStopDtmfTone();
+    method protected void onUnhold();
+    method protected void setActive();
+    method public void setAudioState(android.telecomm.CallAudioState);
+    method protected void setDialing();
+    method protected void setDisconnected(int, java.lang.String);
+    method protected void setHandle(android.net.Uri);
+    method protected void setOnHold();
+    method protected void setRinging();
+    method public static java.lang.String stateToString(int);
+  }
+
+  public static abstract interface Connection.Listener {
+    method public abstract void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
+    method public abstract void onDestroyed(android.telecomm.Connection);
+    method public abstract void onDisconnected(android.telecomm.Connection, int, java.lang.String);
+    method public abstract void onHandleChanged(android.telecomm.Connection, android.net.Uri);
+    method public abstract void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
+    method public abstract void onStateChanged(android.telecomm.Connection, int);
+  }
+
+  public static class Connection.ListenerBase implements android.telecomm.Connection.Listener {
+    ctor public Connection.ListenerBase();
+    method public void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
+    method public void onDestroyed(android.telecomm.Connection);
+    method public void onDisconnected(android.telecomm.Connection, int, java.lang.String);
+    method public void onHandleChanged(android.telecomm.Connection, android.net.Uri);
+    method public void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
+    method public void onStateChanged(android.telecomm.Connection, int);
+  }
+
+  public final class Connection.State {
+    field public static final int ACTIVE = 3; // 0x3
+    field public static final int DIALING = 2; // 0x2
+    field public static final int DISCONNECTED = 5; // 0x5
+    field public static final int HOLDING = 4; // 0x4
+    field public static final int NEW = 0; // 0x0
+    field public static final int RINGING = 1; // 0x1
+  }
+
+  public final class ConnectionRequest {
+    ctor public ConnectionRequest(android.net.Uri, android.os.Bundle);
+    method public android.os.Bundle getExtras();
+    method public android.net.Uri getHandle();
+  }
+
+  public abstract class ConnectionService extends android.telecomm.CallService {
+    ctor public ConnectionService();
+    method public final void abort(java.lang.String);
+    method public final void answer(java.lang.String);
+    method public final void call(android.telecomm.CallInfo);
+    method public final void disconnect(java.lang.String);
+    method public final void hold(java.lang.String);
+    method public final void isCompatibleWith(android.telecomm.CallInfo);
+    method public final void onAudioStateChanged(java.lang.String, android.telecomm.CallAudioState);
+    method public void onCreateConnections(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
+    method public void onCreateIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
+    method public void onFindSubscriptions(android.net.Uri, android.telecomm.Response<android.net.Uri, android.telecomm.Subscription>);
+    method public final void playDtmfTone(java.lang.String, char);
+    method public final void reject(java.lang.String);
+    method public final void setIncomingCallId(java.lang.String, android.os.Bundle);
+    method public final void stopDtmfTone(java.lang.String);
+    method public final void unhold(java.lang.String);
+  }
+
   public class GatewayInfo implements android.os.Parcelable {
     method public int describeContents();
     method public android.net.Uri getGatewayHandle();
@@ -26625,6 +26904,18 @@
     method protected abstract void updateCall(android.telecomm.InCallCall);
   }
 
+  public abstract interface Response {
+    method public abstract void onError(IN, java.lang.String);
+    method public abstract void onResult(IN, OUT...);
+  }
+
+  public class Subscription implements android.os.Parcelable {
+    ctor public Subscription();
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
   public final class TelecommConstants {
     ctor public TelecommConstants();
     field public static final java.lang.String ACTION_CALL_SERVICE;
@@ -27081,6 +27372,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
@@ -29953,6 +30245,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();
@@ -30791,6 +31089,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
@@ -32553,8 +32852,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();
@@ -32606,9 +32907,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);
@@ -32766,6 +33069,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
@@ -36925,6 +37229,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();
@@ -36933,6 +37241,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 36c36a8..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;
@@ -3611,15 +3613,15 @@
             theme.applyStyle(resid, false);
         }
 
-        // Get the primary color and update the RecentsActivityValues for this activity
+        // Get the primary color and update the TaskDescription for this activity
         if (theme != null) {
             TypedArray a = theme.obtainStyledAttributes(com.android.internal.R.styleable.Theme);
             int colorPrimary = a.getColor(com.android.internal.R.styleable.Theme_colorPrimary, 0);
             a.recycle();
             if (colorPrimary != 0) {
-                ActivityManager.RecentsActivityValues v = new ActivityManager.RecentsActivityValues();
-                v.colorPrimary = colorPrimary;
-                setRecentsActivityValues(v);
+                ActivityManager.TaskDescription v = new ActivityManager.TaskDescription(null, null,
+                        colorPrimary);
+                setTaskDescription(v);
             }
         }
     }
@@ -4924,27 +4926,30 @@
     }
 
     /**
-     * Sets information describing this Activity for presentation inside the Recents System UI. When
-     * {@link ActivityManager#getRecentTasks} is called, the activities of each task are
-     * traversed in order from the topmost activity to the bottommost. The traversal continues for
-     * each property until a suitable value is found. For each task those values will be returned in
-     * {@link android.app.ActivityManager.RecentsActivityValues}.
+     * Sets information describing the task with this activity for presentation inside the Recents
+     * System UI. When {@link ActivityManager#getRecentTasks} is called, the activities of each task
+     * are traversed in order from the topmost activity to the bottommost. The traversal continues
+     * for each property until a suitable value is found. For each task the taskDescription will be
+     * returned in {@link android.app.ActivityManager.TaskDescription}.
      *
      * @see ActivityManager#getRecentTasks
-     * @see android.app.ActivityManager.RecentsActivityValues
+     * @see android.app.ActivityManager.TaskDescription
      *
-     * @param values The Recents values that describe this activity.
+     * @param taskDescription The TaskDescription properties that describe the task with this activity
      */
-    public void setRecentsActivityValues(ActivityManager.RecentsActivityValues values) {
-        ActivityManager.RecentsActivityValues activityValues =
-                new ActivityManager.RecentsActivityValues(values);
-        // Scale the icon down to something reasonable
-        if (values.icon != null) {
+    public void setTaskDescription(ActivityManager.TaskDescription taskDescription) {
+        ActivityManager.TaskDescription td;
+        // Scale the icon down to something reasonable if it is provided
+        if (taskDescription.getIcon() != null) {
             final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
-            activityValues.icon = Bitmap.createScaledBitmap(values.icon, size, size, true);
+            final Bitmap icon = Bitmap.createScaledBitmap(taskDescription.getIcon(), size, size, true);
+            td = new ActivityManager.TaskDescription(taskDescription.getLabel(), icon,
+                    taskDescription.getPrimaryColor());
+        } else {
+            td = taskDescription;
         }
         try {
-            ActivityManagerNative.getDefault().setRecentsActivityValues(mToken, activityValues);
+            ActivityManagerNative.getDefault().setTaskDescription(mToken, td);
         } catch (RemoteException e) {
         }
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 1d05320..abcb0d0 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -33,6 +33,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Debug;
@@ -477,65 +478,84 @@
     /**
      * Information you can set and retrieve about the current activity within the recent task list.
      */
-    public static class RecentsActivityValues implements Parcelable {
-        public CharSequence label;
-        public Bitmap icon;
-        public int colorPrimary;
-
-        public RecentsActivityValues(RecentsActivityValues values) {
-            copyFrom(values);
-        }
+    public static class TaskDescription implements Parcelable {
+        private String mLabel;
+        private Bitmap mIcon;
+        private int mColorPrimary;
 
         /**
-         * Creates the RecentsActivityValues to the specified values.
+         * Creates the TaskDescription to the specified values.
          *
-         * @param label A label and description of the current state of this activity.
-         * @param icon An icon that represents the current state of this activity.
-         * @param color A color to override the theme's primary color.
+         * @param label A label and description of the current state of this task.
+         * @param icon An icon that represents the current state of this task.
+         * @param colorPrimary A color to override the theme's primary color.  This color must be opaque.
          */
-        public RecentsActivityValues(CharSequence label, Bitmap icon, int color) {
-            this.label = label;
-            this.icon = icon;
-            this.colorPrimary = color;
+        public TaskDescription(String label, Bitmap icon, int colorPrimary) {
+            if ((colorPrimary != 0) && (Color.alpha(colorPrimary) != 255)) {
+                throw new RuntimeException("A TaskDescription's primary color should be opaque");
+            }
+
+            mLabel = label;
+            mIcon = icon;
+            mColorPrimary = colorPrimary;
         }
 
         /**
-         * Creates the RecentsActivityValues to the specified values.
+         * Creates the TaskDescription to the specified values.
          *
          * @param label A label and description of the current state of this activity.
          * @param icon An icon that represents the current state of this activity.
          */
-        public RecentsActivityValues(CharSequence label, Bitmap icon) {
+        public TaskDescription(String label, Bitmap icon) {
             this(label, icon, 0);
         }
 
         /**
-         * Creates the RecentsActivityValues to the specified values.
+         * Creates the TaskDescription to the specified values.
          *
          * @param label A label and description of the current state of this activity.
          */
-        public RecentsActivityValues(CharSequence label) {
+        public TaskDescription(String label) {
             this(label, null, 0);
         }
 
-        public RecentsActivityValues() {
+        /**
+         * Creates an empty TaskDescription.
+         */
+        public TaskDescription() {
             this(null, null, 0);
         }
 
-        private RecentsActivityValues(Parcel source) {
+        /**
+         * Creates a copy of another TaskDescription.
+         */
+        public TaskDescription(TaskDescription td) {
+            this(td.getLabel(), td.getIcon(), td.getPrimaryColor());
+        }
+
+        private TaskDescription(Parcel source) {
             readFromParcel(source);
         }
 
         /**
-         * Do a shallow copy of another set of activity values.
-         * @hide
+         * @return The label and description of the current state of this task.
          */
-        public void copyFrom(RecentsActivityValues v) {
-            if (v != null) {
-                label = v.label;
-                icon = v.icon;
-                colorPrimary = v.colorPrimary;
-            }
+        public String getLabel() {
+            return mLabel;
+        }
+
+        /**
+         * @return The icon that represents the current state of this task.
+         */
+        public Bitmap getIcon() {
+            return mIcon;
+        }
+
+        /**
+         * @return The color override on the theme's primary color.
+         */
+        public int getPrimaryColor() {
+            return mColorPrimary;
         }
 
         @Override
@@ -545,37 +565,41 @@
 
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            TextUtils.writeToParcel(label, dest,
-                    Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            if (icon == null) {
+            if (mLabel == null) {
                 dest.writeInt(0);
             } else {
                 dest.writeInt(1);
-                icon.writeToParcel(dest, 0);
+                dest.writeString(mLabel);
             }
-            dest.writeInt(colorPrimary);
+            if (mIcon == null) {
+                dest.writeInt(0);
+            } else {
+                dest.writeInt(1);
+                mIcon.writeToParcel(dest, 0);
+            }
+            dest.writeInt(mColorPrimary);
         }
 
         public void readFromParcel(Parcel source) {
-            label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
-            icon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
-            colorPrimary = source.readInt();
+            mLabel = source.readInt() > 0 ? source.readString() : null;
+            mIcon = source.readInt() > 0 ? Bitmap.CREATOR.createFromParcel(source) : null;
+            mColorPrimary = source.readInt();
         }
 
-        public static final Creator<RecentsActivityValues> CREATOR
-                = new Creator<RecentsActivityValues>() {
-            public RecentsActivityValues createFromParcel(Parcel source) {
-                return new RecentsActivityValues(source);
+        public static final Creator<TaskDescription> CREATOR
+                = new Creator<TaskDescription>() {
+            public TaskDescription createFromParcel(Parcel source) {
+                return new TaskDescription(source);
             }
-            public RecentsActivityValues[] newArray(int size) {
-                return new RecentsActivityValues[size];
+            public TaskDescription[] newArray(int size) {
+                return new TaskDescription[size];
             }
         };
 
         @Override
         public String toString() {
-            return "RecentsActivityValues Label: " + label + " Icon: " + icon +
-                    " colorPrimary: " + colorPrimary;
+            return "TaskDescription Label: " + mLabel + " Icon: " + mIcon +
+                    " colorPrimary: " + mColorPrimary;
         }
     }
 
@@ -629,9 +653,11 @@
 
         /**
          * The recent activity values for the highest activity in the stack to have set the values.
-         * {@link Activity#setRecentsActivityValues(android.app.ActivityManager.RecentsActivityValues)}.
+         * {@link Activity#setTaskDescription(android.app.ActivityManager.TaskDescription)}.
+         *
+         * @hide
          */
-        public RecentsActivityValues activityValues;
+        public TaskDescription taskDescription;
 
         public RecentTaskInfo() {
         }
@@ -654,9 +680,9 @@
             ComponentName.writeToParcel(origActivity, dest);
             TextUtils.writeToParcel(description, dest,
                     Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
-            if (activityValues != null) {
+            if (taskDescription != null) {
                 dest.writeInt(1);
-                activityValues.writeToParcel(dest, 0);
+                taskDescription.writeToParcel(dest, 0);
             } else {
                 dest.writeInt(0);
             }
@@ -670,8 +696,8 @@
             baseIntent = source.readInt() > 0 ? Intent.CREATOR.createFromParcel(source) : null;
             origActivity = ComponentName.readFromParcel(source);
             description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
-            activityValues = source.readInt() > 0 ?
-                    RecentsActivityValues.CREATOR.createFromParcel(source) : null;
+            taskDescription = source.readInt() > 0 ?
+                    TaskDescription.CREATOR.createFromParcel(source) : null;
             stackId = source.readInt();
             userId = source.readInt();
         }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index e704a1c..0f65454 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2158,12 +2158,12 @@
             return true;
         }
 
-        case SET_RECENTS_ACTIVITY_VALUES_TRANSACTION: {
+        case SET_TASK_DESCRIPTION_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
-            ActivityManager.RecentsActivityValues values =
-                    ActivityManager.RecentsActivityValues.CREATOR.createFromParcel(data);
-            setRecentsActivityValues(token, values);
+            ActivityManager.TaskDescription values =
+                    ActivityManager.TaskDescription.CREATOR.createFromParcel(data);
+            setTaskDescription(token, values);
             reply.writeNoException();
             return true;
         }
@@ -4967,14 +4967,14 @@
     }
 
     @Override
-    public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues values)
+    public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
         values.writeToParcel(data, 0);
-        mRemote.transact(SET_RECENTS_ACTIVITY_VALUES_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        mRemote.transact(SET_TASK_DESCRIPTION_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
         reply.readException();
         data.recycle();
         reply.recycle();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 71e4e82..5fd288f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3010,19 +3010,10 @@
                 int h;
                 if (w < 0) {
                     Resources res = r.activity.getResources();
-                    Configuration config = res.getConfiguration();
-                    boolean useAlternateRecents = (config.smallestScreenWidthDp < 600);
-                    if (useAlternateRecents) {
-                        int wId = com.android.internal.R.dimen.recents_thumbnail_width;
-                        int hId = com.android.internal.R.dimen.recents_thumbnail_height;
-                        mThumbnailWidth = w = res.getDimensionPixelSize(wId);
-                        mThumbnailHeight = h = res.getDimensionPixelSize(hId);
-                    } else {
-                        mThumbnailHeight = h =
-                            res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
-                        mThumbnailWidth = w =
-                            res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
-                    }
+                    int wId = com.android.internal.R.dimen.recents_thumbnail_width;
+                    int hId = com.android.internal.R.dimen.recents_thumbnail_height;
+                    mThumbnailWidth = w = res.getDimensionPixelSize(wId);
+                    mThumbnailHeight = h = res.getDimensionPixelSize(hId);
                 } else {
                     h = mThumbnailHeight;
                 }
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..ca6b008 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -81,8 +81,8 @@
 import android.net.nsd.NsdManager;
 import android.net.wifi.IWifiManager;
 import android.net.wifi.WifiManager;
-import android.net.wifi.hotspot.IWifiHotspotManager;
-import android.net.wifi.hotspot.WifiHotspotManager;
+import android.net.wifi.passpoint.IPasspointManager;
+import android.net.wifi.passpoint.PasspointManager;
 import android.net.wifi.p2p.IWifiP2pManager;
 import android.net.wifi.p2p.WifiP2pManager;
 import android.nfc.NfcManager;
@@ -578,11 +578,11 @@
                     return new WifiManager(ctx.getOuterContext(), service);
                 }});
 
-        registerService(WIFI_HOTSPOT_SERVICE, new ServiceFetcher() {
+        registerService(WIFI_PASSPOINT_SERVICE, new ServiceFetcher() {
                 public Object createService(ContextImpl ctx) {
-                    IBinder b = ServiceManager.getService(WIFI_HOTSPOT_SERVICE);
-                    IWifiHotspotManager service = IWifiHotspotManager.Stub.asInterface(b);
-                    return new WifiHotspotManager(ctx.getOuterContext(), service);
+                    IBinder b = ServiceManager.getService(WIFI_PASSPOINT_SERVICE);
+                    IPasspointManager service = IPasspointManager.Stub.asInterface(b);
+                    return new PasspointManager(ctx.getOuterContext(), service);
                 }});
 
         registerService(WIFI_P2P_SERVICE, new ServiceFetcher() {
@@ -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/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 8753312..8434c2a 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -440,7 +440,7 @@
     public boolean isInLockTaskMode() throws RemoteException;
 
     /** @hide */
-    public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues values)
+    public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
             throws RemoteException;
 
     /*
@@ -739,7 +739,7 @@
     int START_LOCK_TASK_BY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+214;
     int STOP_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+215;
     int IS_IN_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+216;
-    int SET_RECENTS_ACTIVITY_VALUES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
+    int SET_TASK_DESCRIPTION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+217;
     int START_VOICE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+218;
     int GET_ACTIVITY_OPTIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+219;
     int GET_APP_TASKS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+220;
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/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 00fd7ce..b98e5ae 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -81,8 +81,8 @@
  */
 public final class BluetoothSocket implements Closeable {
     private static final String TAG = "BluetoothSocket";
-    private static final boolean DBG = true;
-    private static final boolean VDBG = false;
+    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
 
     /** @hide */
     public static final int MAX_RFCOMM_CHANNEL = 30;
@@ -185,7 +185,7 @@
         BluetoothSocket as = new BluetoothSocket(this);
         as.mSocketState = SocketState.CONNECTED;
         FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors();
-        if (VDBG) Log.d(TAG, "socket fd passed by stack  fds: " + fds);
+        if (DBG) Log.d(TAG, "socket fd passed by stack  fds: " + fds);
         if(fds == null || fds.length != 1) {
             Log.e(TAG, "socket fd passed from stack failed, fds: " + fds);
             as.close();
@@ -352,24 +352,24 @@
         // read out port number
         try {
             synchronized(this) {
-                if (VDBG) Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " +
+                if (DBG) Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " +
                                 mPfd);
                 if(mSocketState != SocketState.INIT) return EBADFD;
                 if(mPfd == null) return -1;
                 FileDescriptor fd = mPfd.getFileDescriptor();
-                if (VDBG) Log.d(TAG, "bindListen(), new LocalSocket ");
+                if (DBG) Log.d(TAG, "bindListen(), new LocalSocket ");
                 mSocket = new LocalSocket(fd);
-                if (VDBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream() ");
+                if (DBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream() ");
                 mSocketIS = mSocket.getInputStream();
                 mSocketOS = mSocket.getOutputStream();
             }
-            if (VDBG) Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS);
+            if (DBG) Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS);
             int channel = readInt(mSocketIS);
             synchronized(this) {
                 if(mSocketState == SocketState.INIT)
                     mSocketState = SocketState.LISTENING;
             }
-            if (VDBG) Log.d(TAG, "channel: " + channel);
+            if (DBG) Log.d(TAG, "channel: " + channel);
             if (mPort == -1) {
                 mPort = channel;
             } // else ASSERT(mPort == channel)
@@ -439,7 +439,7 @@
 
     @Override
     public void close() throws IOException {
-        if (VDBG) Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " + mSocketState);
+        if (DBG) Log.d(TAG, "close() in, this: " + this + ", channel: " + mPort + ", state: " + mSocketState);
         if(mSocketState == SocketState.CLOSED)
             return;
         else
@@ -449,10 +449,10 @@
                  if(mSocketState == SocketState.CLOSED)
                     return;
                  mSocketState = SocketState.CLOSED;
-                 if (VDBG) Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS +
+                 if (DBG) Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS +
                         ", mSocketOS: " + mSocketOS + "mSocket: " + mSocket);
                  if(mSocket != null) {
-                    if (VDBG) Log.d(TAG, "Closing mSocket: " + mSocket);
+                    if (DBG) Log.d(TAG, "Closing mSocket: " + mSocket);
                     mSocket.shutdownInput();
                     mSocket.shutdownOutput();
                     mSocket.close();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a059e48..f7f51fe 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
@@ -1980,7 +1991,7 @@
             //@hide: NETWORK_STATS_SERVICE,
             //@hide: NETWORK_POLICY_SERVICE,
             WIFI_SERVICE,
-            WIFI_HOTSPOT_SERVICE,
+            WIFI_PASSPOINT_SERVICE,
             WIFI_P2P_SERVICE,
             WIFI_SCANNING_SERVICE,
             NSD_SERVICE,
@@ -2341,13 +2352,13 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
-     * android.net.wifi.hotspot.WifiHotspotManager} for handling management of
-     * Wi-Fi hotspot access.
+     * android.net.wifi.passpoint.PasspointManager} for handling management of
+     * Wi-Fi passpoint access.
      *
      * @see #getSystemService
-     * @see android.net.wifi.hotspot.WifiHotspotManager
+     * @see android.net.wifi.passpoint.PasspointManager
      */
-    public static final String WIFI_HOTSPOT_SERVICE = "wifihotspot";
+    public static final String WIFI_PASSPOINT_SERVICE = "wifipasspoint";
 
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
@@ -2572,13 +2583,24 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
-     * {@link android.hardware.hdmi.HdmiCecManager for controlling and managing
+     * {@link android.hardware.hdmi.HdmiCecManager} for controlling and managing
      * HDMI-CEC protocol.
      *
      * @see #getSystemService
      * @see android.hardware.hdmi.HdmiCecManager
      */
-     public static final String HDMI_CEC_SERVICE = "hdmi_cec";
+    // TODO: Remove this once HdmiControlService is ready.
+    public static final String HDMI_CEC_SERVICE = "hdmi_cec";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@link android.hardware.hdmi.HdmiControlManager} for controlling and managing
+     * HDMI-CEC protocol.
+     *
+     * @see #getSystemService
+     * @see android.hardware.hdmi.HdmiControlManager
+     */
+    public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
 
     /**
      * Use with {@link #getSystemService} to retrieve a
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..7cc6d1d 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;
@@ -29,6 +30,8 @@
  * through the {@link CameraManager CameraManager}
  * interface in addition to through the CameraDevice interface.</p>
  *
+ * <p>{@link CameraCharacteristics} objects are immutable.</p>
+ *
  * @see CameraDevice
  * @see CameraManager
  */
@@ -46,6 +49,14 @@
         mProperties = properties;
     }
 
+    /**
+     * Returns a copy of the underlying {@link CameraMetadataNative}.
+     * @hide
+     */
+    public CameraMetadataNative getNativeCopy() {
+        return new CameraMetadataNative(mProperties);
+    }
+
     @Override
     public <T> T get(Key<T> key) {
         return mProperties.get(key);
@@ -316,8 +327,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 +404,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 +669,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 +715,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 +972,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 +1114,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 +1523,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..f91fcb9 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>
@@ -31,6 +33,8 @@
  * capture. The result also includes additional metadata about the state of the
  * camera device during the capture.</p>
  *
+ * <p>{@link CameraCharacteristics} objects are immutable.</p>
+ *
  */
 public final class CaptureResult extends CameraMetadata {
 
@@ -56,6 +60,14 @@
         mSequenceId = sequenceId;
     }
 
+    /**
+     * Returns a copy of the underlying {@link CameraMetadataNative}.
+     * @hide
+     */
+    public CameraMetadataNative getNativeCopy() {
+        return new CameraMetadataNative(mResults);
+    }
+
     @Override
     public <T> T get(Key<T> key) {
         return mResults.get(key);
@@ -1512,8 +1524,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 +2072,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 +2447,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..b328f57 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..a71a74d 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;
@@ -165,8 +171,15 @@
     public static final int POWER_STATUS_UNKNOWN = -1;
     public static final int POWER_STATUS_ON = 0;
     public static final int POWER_STATUS_STANDBY = 1;
-    public static final int POWER_TRANSIENT_TO_ON = 2;
-    public static final int POWER_TRANSIENT_TO_STANDBY = 3;
+    public static final int POWER_STATUS_TRANSIENT_TO_ON = 2;
+    public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3;
+
+    public static final int RESULT_SUCCESS = 0;
+    public static final int RESULT_TIMEOUT = 1;
+    public static final int RESULT_SOURCE_NOT_AVAILABLE = 2;
+    public static final int RESULT_TARGET_NOT_AVAILABLE = 3;
+    public static final int RESULT_ALREADY_IN_PROGRESS = 4;
+    public static final int RESULT_EXCEPTION = 5;
 
     private static final int[] ADDRESS_TO_TYPE = {
         DEVICE_TV,  // ADDR_TV
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
new file mode 100644
index 0000000..a3f27b9
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -0,0 +1,76 @@
+/*
+ * 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.hardware.hdmi;
+
+import android.annotation.Nullable;
+/**
+ * The {@link HdmiControlManager} class is used to send HDMI control messages
+ * to attached CEC devices.
+ *
+ * <p>Provides various HDMI client instances that represent HDMI-CEC logical devices
+ * hosted in the system. {@link #getTvClient()}, for instance will return an
+ * {@link HdmiTvClient} object if the system is configured to host one. Android system
+ * can host more than one logical CEC devices. If multiple types are configured they
+ * all work as if they were independent logical devices running in the system.
+ */
+public final class HdmiControlManager {
+    @Nullable private final IHdmiControlService mService;
+
+    /**
+     * @hide - hide this constructor because it has a parameter of type
+     * IHdmiControlService, which is a system private class. The right way
+     * to create an instance of this class is using the factory
+     * Context.getSystemService.
+     */
+    public HdmiControlManager(IHdmiControlService service) {
+        mService = service;
+    }
+
+    /**
+     * Gets an object that represents a HDMI-CEC logical device of type playback on the system.
+     *
+     * <p>Used to send HDMI control messages to other devices like TV or audio amplifier through
+     * HDMI bus. It is also possible to communicate with other logical devices hosted in the same
+     * system if the system is configured to host more than one type of HDMI-CEC logical devices.
+     *
+     * @return {@link HdmiPlaybackClient} instance. {@code null} on failure.
+     */
+    @Nullable
+    public HdmiPlaybackClient getPlaybackClient() {
+        if (mService == null) {
+            return null;
+        }
+        return new HdmiPlaybackClient(mService);
+    }
+
+    /**
+     * Gets an object that represents a HDMI-CEC logical device of type TV on the system.
+     *
+     * <p>Used to send HDMI control messages to other devices and manage them through
+     * HDMI bus. It is also possible to communicate with other logical devices hosted in the same
+     * system if the system is configured to host more than one type of HDMI-CEC logical devices.
+     *
+     * @return {@link HdmiTvClient} instance. {@code null} on failure.
+     */
+    @Nullable
+    public HdmiTvClient getTvClient() {
+        if (mService == null) {
+            return null;
+        }
+        return new HdmiTvClient(mService);
+    }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
new file mode 100644
index 0000000..83da29a
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
@@ -0,0 +1,116 @@
+/*
+ * 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.hardware.hdmi;
+
+import android.os.RemoteException;
+
+import android.util.Log;
+
+/**
+ * HdmiPlaybackClient represents HDMI-CEC logical device of type Playback
+ * in the Android system which acts as a playback device such as set-top box.
+ * It provides with methods that control, get information from TV/Display device
+ * connected through HDMI bus.
+ */
+public final class HdmiPlaybackClient {
+    private static final String TAG = "HdmiPlaybackClient";
+
+    private final IHdmiControlService mService;
+
+    /**
+     * Listener used by the client to get the result of one touch play operation.
+     */
+    public interface OneTouchPlayCallback {
+        /**
+         * Called when the result of the feature one touch play is returned.
+         *
+         * @param result the result of the operation. {@link HdmiCec#RESULT_SUCCESS}
+         *         if successful.
+         */
+        public void onComplete(int result);
+    }
+
+    /**
+     * Listener used by the client to get display device status.
+     */
+    public interface DisplayStatusCallback {
+        /**
+         * Called when display device status is reported.
+         *
+         * @param status display device status
+         * @see {@link HdmiCec#POWER_STATUS_ON}
+         * @see {@link HdmiCec#POWER_STATUS_STANDBY}
+         * @see {@link HdmiCec#POWER_STATUS_TRANSIENT_TO_ON}
+         * @see {@link HdmiCec#POWER_STATUS_TRANSIENT_TO_STANDBY}
+         * @see {@link HdmiCec#POWER_STATUS_UNKNOWN}
+         */
+        public void onComplete(int status);
+    }
+
+    HdmiPlaybackClient(IHdmiControlService service) {
+        mService = service;
+    }
+
+    /**
+     * Perform the feature 'one touch play' from playback device to turn on display
+     * and switch the input.
+     *
+     * @param callback {@link OneTouchPlayCallback} object to get informed
+     *         of the result
+     */
+    public void oneTouchPlay(OneTouchPlayCallback callback) {
+        // TODO: Use PendingResult.
+        try {
+            mService.oneTouchPlay(getCallbackWrapper(callback));
+        } catch (RemoteException e) {
+            Log.e(TAG, "oneTouchPlay threw exception ", e);
+        }
+    }
+
+    /**
+     * Get the status of display device connected through HDMI bus.
+     *
+     * @param callback {@link DisplayStatusCallback} object to get informed
+     *         of the result
+     */
+    public void queryDisplayStatus(DisplayStatusCallback callback) {
+        // TODO: PendingResult.
+        try {
+            mService.oneTouchPlay(getCallbackWrapper(callback));
+        } catch (RemoteException e) {
+            Log.e(TAG, "queryDisplayStatus threw exception ", e);
+        }
+    }
+
+    private IHdmiControlCallback getCallbackWrapper(final OneTouchPlayCallback callback) {
+        return new IHdmiControlCallback.Stub() {
+            @Override
+            public void onComplete(int result) {
+                callback.onComplete(result);
+            }
+        };
+    }
+
+    private IHdmiControlCallback getCallbackWrapper(final DisplayStatusCallback callback) {
+        return new IHdmiControlCallback.Stub() {
+            @Override
+            public void onComplete(int status) {
+                callback.onComplete(status);
+            }
+        };
+    }
+}
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
new file mode 100644
index 0000000..73c7247
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -0,0 +1,31 @@
+/*
+ * 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.hardware.hdmi;
+
+/**
+ * HdmiTvClient represents HDMI-CEC logical device of type TV in the Android system
+ * which acts as TV/Display. It provides with methods that manage, interact with other
+ * devices on the CEC bus.
+ */
+public final class HdmiTvClient {
+    private static final String TAG = "HdmiTvClient";
+
+    private final IHdmiControlService mService;
+
+    HdmiTvClient(IHdmiControlService service) {
+        mService = service;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java b/core/java/android/hardware/hdmi/IHdmiControlCallback.aidl
similarity index 72%
copy from packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java
copy to core/java/android/hardware/hdmi/IHdmiControlCallback.aidl
index 158e9c1..ef3dd47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java
+++ b/core/java/android/hardware/hdmi/IHdmiControlCallback.aidl
@@ -14,9 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.policy;
+package android.hardware.hdmi;
 
-/** Common interface for items requiring manual cleanup. **/
-public interface Disposable {
-    void dispose();
+/**
+ * Callback interface definition for HDMI client to get informed of
+ * the result of various API invocation.
+ *
+ * @hide
+ */
+oneway interface IHdmiControlCallback {
+    void onComplete(int result);
 }
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
new file mode 100644
index 0000000..f790ed9
--- /dev/null
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.hardware.hdmi;
+
+import android.hardware.hdmi.HdmiCecMessage;
+import android.hardware.hdmi.IHdmiControlCallback;
+
+/**
+ * Binder interface that clients running in the application process
+ * will use to perform HDMI-CEC features by communicating with other devices
+ * on the bus.
+ *
+ * @hide
+ */
+interface IHdmiControlService {
+    int oneTouchPlay(IHdmiControlCallback callback);
+    int queryDisplayStatus(IHdmiControlCallback callback);
+}
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index a725bec..d07c0b61 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -39,7 +39,8 @@
  * <ul>
  * <li>An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}).
  * The address must be unicast, as multicast addresses cannot be assigned to interfaces.
- * <li>Address flags: A bitmask of {@code IFA_F_*} values representing properties of the address.
+ * <li>Address flags: A bitmask of {@code IFA_F_*} values representing properties
+ * of the address.
  * <li>Address scope: An integer defining the scope in which the address is unique (e.g.,
  * {@code RT_SCOPE_LINK} or {@code RT_SCOPE_SITE}).
  * <ul>
@@ -47,10 +48,9 @@
  * When constructing a {@code LinkAddress}, the IP address and prefix are required. The flags and
  * scope are optional. If they are not specified, the flags are set to zero, and the scope will be
  * determined based on the IP address (e.g., link-local addresses will be created with a scope of
- * {@code RT_SCOPE_LINK}, global addresses with {@code RT_SCOPE_UNIVERSE}, etc.) If they are
- * specified, they are not checked for validity.
+ * {@code RT_SCOPE_LINK}, global addresses with {@code RT_SCOPE_UNIVERSE},
+ * etc.) If they are specified, they are not checked for validity.
  *
- * @hide
  */
 public class LinkAddress implements Parcelable {
     /**
@@ -119,6 +119,10 @@
      * the specified flags and scope. Flags and scope are not checked for validity.
      * @param address The IP address.
      * @param prefixLength The prefix length.
+     * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
+     * @param scope An integer defining the scope in which the address is unique (e.g.,
+     *              {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
+     * @hide
      */
     public LinkAddress(InetAddress address, int prefixLength, int flags, int scope) {
         init(address, prefixLength, flags, scope);
@@ -129,6 +133,7 @@
      * The flags are set to zero and the scope is determined from the address.
      * @param address The IP address.
      * @param prefixLength The prefix length.
+     * @hide
      */
     public LinkAddress(InetAddress address, int prefixLength) {
         this(address, prefixLength, 0, 0);
@@ -139,6 +144,7 @@
      * Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}.
      * The flags are set to zero and the scope is determined from the address.
      * @param interfaceAddress The interface address.
+     * @hide
      */
     public LinkAddress(InterfaceAddress interfaceAddress) {
         this(interfaceAddress.getAddress(),
@@ -149,6 +155,7 @@
      * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
      * "2001:db8::1/64". The flags are set to zero and the scope is determined from the address.
      * @param string The string to parse.
+     * @hide
      */
     public LinkAddress(String address) {
         this(address, 0, 0);
@@ -161,6 +168,7 @@
      * @param string The string to parse.
      * @param flags The address flags.
      * @param scope The address scope.
+     * @hide
      */
     public LinkAddress(String address, int flags, int scope) {
         InetAddress inetAddress = null;
@@ -220,9 +228,10 @@
     }
 
     /**
-     * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress} represent
-     * the same address. Two LinkAddresses represent the same address if they have the same IP
-     * address and prefix length, even if their properties are different.
+     * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress}
+     * represent the same address. Two {@code LinkAddresses} represent the same address
+     * if they have the same IP address and prefix length, even if their properties are
+     * different.
      *
      * @param other the {@code LinkAddress} to compare to.
      * @return {@code true} if both objects have the same address and prefix length, {@code false}
@@ -233,28 +242,28 @@
     }
 
     /**
-     * Returns the InetAddress of this address.
+     * Returns the {@link InetAddress} of this {@code LinkAddress}.
      */
     public InetAddress getAddress() {
         return address;
     }
 
     /**
-     * Returns the prefix length of this address.
+     * Returns the prefix length of this {@code LinkAddress}.
      */
     public int getNetworkPrefixLength() {
         return prefixLength;
     }
 
     /**
-     * Returns the flags of this address.
+     * Returns the flags of this {@code LinkAddress}.
      */
     public int getFlags() {
         return flags;
     }
 
     /**
-     * Returns the scope of this address.
+     * Returns the scope of this {@code LinkAddress}.
      */
     public int getScope() {
         return scope;
@@ -262,6 +271,7 @@
 
     /**
      * Returns true if this {@code LinkAddress} is global scope and preferred.
+     * @hide
      */
     public boolean isGlobalPreferred() {
         return (scope == RT_SCOPE_UNIVERSE &&
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/Network.java b/core/java/android/net/Network.java
index ac1289b..a99da78 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -20,20 +20,35 @@
 import android.os.Parcel;
 
 import java.net.InetAddress;
+import java.net.Socket;
 import java.net.UnknownHostException;
+import javax.net.SocketFactory;
 
 /**
- * Identifies the Network.
+ * Identifies a {@code Network}.  This is supplied to applications via
+ * {@link ConnectivityManager#NetworkCallbacks} in response to
+ * {@link ConnectivityManager#requestNetwork} or {@link ConnectivityManager#listenForNetwork}.
+ * It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis
+ * through a targeted {@link SocketFactory} or process-wide via {@link #bindProcess}.
  * @hide
  */
 public class Network implements Parcelable {
 
+    /**
+     * @hide
+     */
     public final int netId;
 
+    /**
+     * @hide
+     */
     public Network(int netId) {
         this.netId = netId;
     }
 
+    /**
+     * @hide
+     */
     public Network(Network that) {
         this.netId = that.netId;
     }
@@ -64,6 +79,45 @@
         return InetAddress.getByNameOnNet(host, netId);
     }
 
+    /**
+     * Returns a {@link SocketFactory} bound to this network.  Any {@link Socket} created by
+     * this factory will have its traffic sent over this {@code Network}.  Note that if this
+     * {@code Network} ever disconnects, this factory and any {@link Socket} it produced in the
+     * past or future will cease to work.
+     *
+     * @return a {@link SocketFactory} which produces {@link Socket} instances bound to this
+     *         {@code Network}.
+     */
+    public SocketFactory socketFactory() {
+        return null;
+    }
+
+    /**
+     * Binds the current process to this network.  All sockets created in the future (and not
+     * explicitly bound via a bound {@link SocketFactory} (see {@link Network#socketFactory})
+     * will be bound to this network.  Note that if this {@code Network} ever disconnects
+     * all sockets created in this way will cease to work.  This is by design so an application
+     * doesn't accidentally use sockets it thinks are still bound to a particular {@code Network}.
+     */
+    public void bindProcess() {
+    }
+
+    /**
+     * A static utility method to return any {@code Network} currently bound by this process.
+     *
+     * @return {@code Network} to which this process is bound.
+     */
+    public static Network getProcessBoundNetwork() {
+        return null;
+    }
+
+    /**
+     * Clear any process specific {@code Network} binding.  This reverts a call to
+     * {@link Network#bindProcess}.
+     */
+    public static void unbindProcess() {
+    }
+
     // implement the Parcelable interface
     public int describeContents() {
         return 0;
@@ -84,4 +138,14 @@
                 return new Network[size];
             }
     };
+
+    public boolean equals(Object obj) {
+        if (obj instanceof Network == false) return false;
+        Network other = (Network)obj;
+        return this.netId == other.netId;
+    }
+
+    public int hashCode() {
+        return netId * 11;
+    }
 }
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/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 8005e5c..35274f1 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -30,13 +30,31 @@
 import java.util.Set;
 
 /**
- * A class representing the capabilities of a network
- * @hide
+ * This class represents the capabilities of a network.  This is used both to specify
+ * needs to {@link ConnectivityManager} and when inspecting a network.
+ *
+ * Note that this replaces the old {@link ConnectivityManager#TYPE_MOBILE} method
+ * of network selection.  Rather than indicate a need for Wi-Fi because an application
+ * needs high bandwidth and risk obselence when a new, fast network appears (like LTE),
+ * the application should specify it needs high bandwidth.  Similarly if an application
+ * needs an unmetered network for a bulk transfer it can specify that rather than assuming
+ * all cellular based connections are metered and all Wi-Fi based connections are not.
  */
 public final class NetworkCapabilities implements Parcelable {
     private static final String TAG = "NetworkCapabilities";
     private static final boolean DBG = false;
 
+    public NetworkCapabilities() {
+    }
+
+    public NetworkCapabilities(NetworkCapabilities nc) {
+        if (nc != null) {
+            mNetworkCapabilities = nc.mNetworkCapabilities;
+            mTransportTypes = nc.mTransportTypes;
+            mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
+            mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
+        }
+    }
 
     /**
      * Represents the network's capabilities.  If any are specified they will be satisfied
@@ -45,28 +63,99 @@
     private long mNetworkCapabilities = (1 << NET_CAPABILITY_NOT_RESTRICTED);
 
     /**
-     * Values for NetworkCapabilities.  Roughly matches/extends deprecated
-     * ConnectivityManager TYPE_*
+     * Indicates this is a network that has the ability to reach the
+     * carrier's MMSC for sending and receiving MMS messages.
      */
     public static final int NET_CAPABILITY_MMS            = 0;
+
+    /**
+     * Indicates this is a network that has the ability to reach the carrier's
+     * SUPL server, used to retrieve GPS information.
+     */
     public static final int NET_CAPABILITY_SUPL           = 1;
+
+    /**
+     * Indicates this is a network that has the ability to reach the carrier's
+     * DUN or tethering gateway.
+     */
     public static final int NET_CAPABILITY_DUN            = 2;
+
+    /**
+     * Indicates this is a network that has the ability to reach the carrier's
+     * FOTA portal, used for over the air updates.
+     */
     public static final int NET_CAPABILITY_FOTA           = 3;
+
+    /**
+     * Indicates this is a network that has the ability to reach the carrier's
+     * IMS servers, used for network registration and signaling.
+     */
     public static final int NET_CAPABILITY_IMS            = 4;
+
+    /**
+     * Indicates this is a network that has the ability to reach the carrier's
+     * CBS servers, used for carrier specific services.
+     */
     public static final int NET_CAPABILITY_CBS            = 5;
+
+    /**
+     * Indicates this is a network that has the ability to reach a Wi-Fi direct
+     * peer.
+     */
     public static final int NET_CAPABILITY_WIFI_P2P       = 6;
+
+    /**
+     * Indicates this is a network that has the ability to reach a carrier's
+     * Initial Attach servers.
+     */
     public static final int NET_CAPABILITY_IA             = 7;
+
+    /**
+     * Indicates this is a network that has the ability to reach a carrier's
+     * RCS servers, used for Rich Communication Services.
+     */
     public static final int NET_CAPABILITY_RCS            = 8;
+
+    /**
+     * Indicates this is a network that has the ability to reach a carrier's
+     * XCAP servers, used for configuration and control.
+     */
     public static final int NET_CAPABILITY_XCAP           = 9;
+
+    /**
+     * Indicates this is a network that has the ability to reach a carrier's
+     * Emergency IMS servers, used for network signaling during emergency calls.
+     */
     public static final int NET_CAPABILITY_EIMS           = 10;
+
+    /**
+     * Indicates that this network is unmetered.
+     */
     public static final int NET_CAPABILITY_NOT_METERED    = 11;
+
+    /**
+     * Indicates that this network should be able to reach the internet.
+     */
     public static final int NET_CAPABILITY_INTERNET       = 12;
-    /** Set by default */
+
+    /**
+     * Indicates that this network is available for general use.  If this is not set
+     * applications should not attempt to communicate on this network.  Note that this
+     * is simply informative and not enforcement - enforcement is handled via other means.
+     * Set by default.
+     */
     public static final int NET_CAPABILITY_NOT_RESTRICTED = 13;
 
     private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
     private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_RESTRICTED;
 
+    /**
+     * Adds the given capability to this {@code NetworkCapability} instance.
+     * Multiple capabilities may be applied sequentially.  Note that when searching
+     * for a network to satisfy a request, all capabilities requested must be satisfied.
+     *
+     * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added.
+     */
     public void addNetworkCapability(int networkCapability) {
         if (networkCapability < MIN_NET_CAPABILITY ||
                 networkCapability > MAX_NET_CAPABILITY) {
@@ -74,6 +163,12 @@
         }
         mNetworkCapabilities |= 1 << networkCapability;
     }
+
+    /**
+     * Removes (if found) the given capability from this {@code NetworkCapability} instance.
+     *
+     * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed.
+     */
     public void removeNetworkCapability(int networkCapability) {
         if (networkCapability < MIN_NET_CAPABILITY ||
                 networkCapability > MAX_NET_CAPABILITY) {
@@ -81,9 +176,23 @@
         }
         mNetworkCapabilities &= ~(1 << networkCapability);
     }
+
+    /**
+     * Gets all the capabilities set on this {@code NetworkCapability} instance.
+     *
+     * @return a {@link Collection} of {@code NetworkCapabilities.NET_CAPABILITY_*} values
+     *         for this instance.
+     */
     public Collection<Integer> getNetworkCapabilities() {
         return enumerateBits(mNetworkCapabilities);
     }
+
+    /**
+     * Tests for the presence of a capabilitity on this instance.
+     *
+     * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for.
+     * @return {@code true} if set on this instance.
+     */
     public boolean hasCapability(int networkCapability) {
         if (networkCapability < MIN_NET_CAPABILITY ||
                 networkCapability > MAX_NET_CAPABILITY) {
@@ -124,31 +233,74 @@
     private long mTransportTypes;
 
     /**
-     * Values for TransportType
+     * Indicates this network uses a Cellular transport.
      */
     public static final int TRANSPORT_CELLULAR = 0;
+
+    /**
+     * Indicates this network uses a Wi-Fi transport.
+     */
     public static final int TRANSPORT_WIFI = 1;
+
+    /**
+     * Indicates this network uses a Bluetooth transport.
+     */
     public static final int TRANSPORT_BLUETOOTH = 2;
+
+    /**
+     * Indicates this network uses an Ethernet transport.
+     */
     public static final int TRANSPORT_ETHERNET = 3;
 
     private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
     private static final int MAX_TRANSPORT = TRANSPORT_ETHERNET;
 
+    /**
+     * Adds the given transport type to this {@code NetworkCapability} instance.
+     * Multiple transports may be applied sequentially.  Note that when searching
+     * for a network to satisfy a request, any listed in the request will satisfy the request.
+     * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a
+     * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network
+     * to be selected.  This is logically different than
+     * {@code NetworkCapabilities.NET_CAPABILITY_*} listed above.
+     *
+     * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be added.
+     */
     public void addTransportType(int transportType) {
         if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
             throw new IllegalArgumentException("TransportType out of range");
         }
         mTransportTypes |= 1 << transportType;
     }
+
+    /**
+     * Removes (if found) the given transport from this {@code NetworkCapability} instance.
+     *
+     * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be removed.
+     */
     public void removeTransportType(int transportType) {
         if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
             throw new IllegalArgumentException("TransportType out of range");
         }
         mTransportTypes &= ~(1 << transportType);
     }
+
+    /**
+     * Gets all the transports set on this {@code NetworkCapability} instance.
+     *
+     * @return a {@link Collection} of {@code NetworkCapabilities.TRANSPORT_*} values
+     *         for this instance.
+     */
     public Collection<Integer> getTransportTypes() {
         return enumerateBits(mTransportTypes);
     }
+
+    /**
+     * Tests for the presence of a transport on this instance.
+     *
+     * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be tested for.
+     * @return {@code true} if set on this instance.
+     */
     public boolean hasTransport(int transportType) {
         if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) {
             return false;
@@ -175,15 +327,58 @@
     private int mLinkUpBandwidthKbps;
     private int mLinkDownBandwidthKbps;
 
+    /**
+     * Sets the upstream bandwidth for this network in Kbps.  This always only refers to
+     * the estimated first hop transport bandwidth.
+     * <p>
+     * Note that when used to request a network, this specifies the minimum acceptable.
+     * When received as the state of an existing network this specifies the typical
+     * first hop bandwidth expected.  This is never measured, but rather is inferred
+     * from technology type and other link parameters.  It could be used to differentiate
+     * between very slow 1xRTT cellular links and other faster networks or even between
+     * 802.11b vs 802.11AC wifi technologies.  It should not be used to differentiate between
+     * fast backhauls and slow backhauls.
+     *
+     * @param upKbps the estimated first hop upstream (device to network) bandwidth.
+     */
     public void setLinkUpstreamBandwidthKbps(int upKbps) {
         mLinkUpBandwidthKbps = upKbps;
     }
+
+    /**
+     * Retrieves the upstream bandwidth for this network in Kbps.  This always only refers to
+     * the estimated first hop transport bandwidth.
+     *
+     * @return The estimated first hop upstream (device to network) bandwidth.
+     */
     public int getLinkUpstreamBandwidthKbps() {
         return mLinkUpBandwidthKbps;
     }
+
+    /**
+     * Sets the downstream bandwidth for this network in Kbps.  This always only refers to
+     * the estimated first hop transport bandwidth.
+     * <p>
+     * Note that when used to request a network, this specifies the minimum acceptable.
+     * When received as the state of an existing network this specifies the typical
+     * first hop bandwidth expected.  This is never measured, but rather is inferred
+     * from technology type and other link parameters.  It could be used to differentiate
+     * between very slow 1xRTT cellular links and other faster networks or even between
+     * 802.11b vs 802.11AC wifi technologies.  It should not be used to differentiate between
+     * fast backhauls and slow backhauls.
+     *
+     * @param downKbps the estimated first hop downstream (network to device) bandwidth.
+     */
     public void setLinkDownstreamBandwidthKbps(int downKbps) {
         mLinkDownBandwidthKbps = downKbps;
     }
+
+    /**
+     * Retrieves the downstream bandwidth for this network in Kbps.  This always only refers to
+     * the estimated first hop transport bandwidth.
+     *
+     * @return The estimated first hop downstream (network to device) bandwidth.
+     */
     public int getLinkDownstreamBandwidthKbps() {
         return mLinkDownBandwidthKbps;
     }
@@ -243,19 +438,6 @@
                 (mLinkDownBandwidthKbps * 13));
     }
 
-    public NetworkCapabilities() {
-    }
-
-    public NetworkCapabilities(NetworkCapabilities nc) {
-        if (nc != null) {
-            mNetworkCapabilities = nc.mNetworkCapabilities;
-            mTransportTypes = nc.mTransportTypes;
-            mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
-            mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
-        }
-    }
-
-    // Parcelable
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index b3ae3f5..80074a5 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -22,11 +22,19 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
+ * Defines a request for a network, made by calling {@link ConnectivityManager.requestNetwork}.
+ *
+ * This token records the {@link NetworkCapabilities} used to make the request and identifies
+ * the request.  It should be used to release the request via
+ * {@link ConnectivityManager.releaseNetworkRequest} when the network is no longer desired.
  * @hide
  */
 public class NetworkRequest implements Parcelable {
     /**
-     * The NetworkCapabilities that define this request
+     * The {@link NetworkCapabilities} that define this request.  This should not be modified.
+     * The networkCapabilities of the request are set when
+     * {@link ConnectivityManager.requestNetwork} is called and the value is presented here
+     * as a convenient reminder of what was requested.
      */
     public final NetworkCapabilities networkCapabilities;
 
@@ -34,7 +42,7 @@
      * Identifies the request.  NetworkRequests should only be constructed by
      * the Framework and given out to applications as tokens to be used to identify
      * the request.
-     * TODO - make sure this input is checked whenever a NR is passed in a public API
+     * @hide
      */
     public final int requestId;
 
@@ -45,31 +53,18 @@
      */
     public final boolean needsBroadcasts;
 
-    private static final AtomicInteger sNextRequestId = new AtomicInteger(1);
-
     /**
      * @hide
      */
-    public NetworkRequest(NetworkCapabilities nc) {
-        this(nc, false, sNextRequestId.getAndIncrement());
-    }
-
-    /**
-     * @hide
-     */
-    public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts) {
-        this(nc, needsBroadcasts, sNextRequestId.getAndIncrement());
-    }
-
-    /**
-     * @hide
-     */
-    private NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) {
+    public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) {
         requestId = rId;
         networkCapabilities = nc;
         this.needsBroadcasts = needsBroadcasts;
     }
 
+    /**
+     * @hide
+     */
     public NetworkRequest(NetworkRequest that) {
         networkCapabilities = new NetworkCapabilities(that.networkCapabilities);
         requestId = that.requestId;
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 1d051dd..ad8e4f7 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -25,22 +25,26 @@
 import java.net.Inet6Address;
 
 import java.util.Collection;
+import java.util.Objects;
 
 /**
- * A simple container for route information.
+ * Represents a network route.
+ * <p>
+ * This is used both to describe static network configuration and live network
+ * configuration information.
  *
- * In order to be used, a route must have a destination prefix and:
- *
- * - A gateway address (next-hop, for gatewayed routes), or
- * - An interface (for directly-connected routes), or
- * - Both a gateway and an interface.
- *
- * This class does not enforce these constraints because there is code that
- * uses RouteInfo objects to store directly-connected routes without interfaces.
- * Such objects cannot be used directly, but can be put into a LinkProperties
- * object which then specifies the interface.
- *
- * @hide
+ * A route contains three pieces of information:
+ * <ul>
+ * <li>a destination {@link LinkAddress} for directly-connected subnets.  If this is
+ *     {@code null} it indicates a default route of the address family (IPv4 or IPv6)
+ *     implied by the gateway IP address.
+ * <li>a gateway {@link InetAddress} for default routes.  If this is {@code null} it
+ *     indicates a directly-connected route.
+ * <li>an interface (which may be unspecified).
+ * </ul>
+ * Either the destination or the gateway may be {@code null}, but not both.  If the
+ * destination and gateway are both specified, they must be of the same address family
+ * (IPv4 or IPv6).
  */
 public class RouteInfo implements Parcelable {
     /**
@@ -67,10 +71,10 @@
      *
      * If destination is null, then gateway must be specified and the
      * constructed route is either the IPv4 default route <code>0.0.0.0</code>
-     * if @gateway is an instance of {@link Inet4Address}, or the IPv6 default
+     * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
      * route <code>::/0</code> if gateway is an instance of
      * {@link Inet6Address}.
-     *
+     * <p>
      * destination and gateway may not both be null.
      *
      * @param destination the destination prefix
@@ -102,28 +106,64 @@
 
         mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(),
                 destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
+        if ((destination.getAddress() instanceof Inet4Address &&
+                 (gateway instanceof Inet4Address == false)) ||
+                (destination.getAddress() instanceof Inet6Address &&
+                 (gateway instanceof Inet6Address == false))) {
+            throw new IllegalArgumentException("address family mismatch in RouteInfo constructor");
+        }
         mGateway = gateway;
         mInterface = iface;
         mIsDefault = isDefault();
         mIsHost = isHost();
     }
 
+    /**
+     * Constructs a {@code RouteInfo} object.
+     *
+     * If destination is null, then gateway must be specified and the
+     * constructed route is either the IPv4 default route <code>0.0.0.0</code>
+     * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
+     * route <code>::/0</code> if gateway is an instance of {@link Inet6Address}.
+     * <p>
+     * Destination and gateway may not both be null.
+     *
+     * @param destination the destination address and prefix in a {@link LinkAddress}
+     * @param gateway the {@link InetAddress} to route packets through
+     */
     public RouteInfo(LinkAddress destination, InetAddress gateway) {
         this(destination, gateway, null);
     }
 
+    /**
+     * Constructs a default {@code RouteInfo} object.
+     *
+     * @param gateway the {@link InetAddress} to route packets through
+     */
     public RouteInfo(InetAddress gateway) {
         this(null, gateway, null);
     }
 
-    public RouteInfo(LinkAddress host) {
-        this(host, null, null);
+    /**
+     * Constructs a {@code RouteInfo} object representing a direct connected subnet.
+     *
+     * @param destination the {@link LinkAddress} describing the address and prefix
+     *                    length of the subnet.
+     */
+    public RouteInfo(LinkAddress destination) {
+        this(destination, null, null);
     }
 
+    /**
+     * @hide
+     */
     public static RouteInfo makeHostRoute(InetAddress host, String iface) {
         return makeHostRoute(host, null, iface);
     }
 
+    /**
+     * @hide
+     */
     public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway, String iface) {
         if (host == null) return null;
 
@@ -153,31 +193,108 @@
         return val;
     }
 
-
+    /**
+     * Retrieves the destination address and prefix length in the form of a {@link LinkAddress}.
+     *
+     * @return {@link LinkAddress} specifying the destination.  This is never {@code null}.
+     */
     public LinkAddress getDestination() {
         return mDestination;
     }
 
+    /**
+     * Retrieves the gateway or next hop {@link InetAddress} for this route.
+     *
+     * @return {@link InetAddress} specifying the gateway or next hop.  This may be
+     &                             {@code null} for a directly-connected route."
+     */
     public InetAddress getGateway() {
         return mGateway;
     }
 
+    /**
+     * Retrieves the interface used for this route if specified, else {@code null}.
+     *
+     * @return The name of the interface used for this route.
+     */
     public String getInterface() {
         return mInterface;
     }
 
+    /**
+     * Indicates if this route is a default route (ie, has no destination specified).
+     *
+     * @return {@code true} if the destination has a prefix length of 0.
+     */
     public boolean isDefaultRoute() {
         return mIsDefault;
     }
 
+    /**
+     * Indicates if this route is a host route (ie, matches only a single host address).
+     *
+     * @return {@code true} if the destination has a prefix length of 32/128 for v4/v6.
+     * @hide
+     */
     public boolean isHostRoute() {
         return mIsHost;
     }
 
+    /**
+     * Indicates if this route has a next hop ({@code true}) or is directly-connected
+     * ({@code false}).
+     *
+     * @return {@code true} if a gateway is specified
+     * @hide
+     */
     public boolean hasGateway() {
         return mHasGateway;
     }
 
+    /**
+     * Determines whether the destination and prefix of this route includes the specified
+     * address.
+     *
+     * @param destination A {@link InetAddress} to test to see if it would match this route.
+     * @return {@code true} if the destination and prefix length cover the given address.
+     */
+    public boolean matches(InetAddress destination) {
+        if (destination == null) return false;
+
+        // match the route destination and destination with prefix length
+        InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
+                mDestination.getNetworkPrefixLength());
+
+        return mDestination.getAddress().equals(dstNet);
+    }
+
+    /**
+     * Find the route from a Collection of routes that best matches a given address.
+     * May return null if no routes are applicable.
+     * @param routes a Collection of RouteInfos to chose from
+     * @param dest the InetAddress your trying to get to
+     * @return the RouteInfo from the Collection that best fits the given address
+     *
+     * @hide
+     */
+    public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
+        if ((routes == null) || (dest == null)) return null;
+
+        RouteInfo bestRoute = null;
+        // pick a longest prefix match under same address type
+        for (RouteInfo route : routes) {
+            if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) {
+                if ((bestRoute != null) &&
+                        (bestRoute.mDestination.getNetworkPrefixLength() >=
+                        route.mDestination.getNetworkPrefixLength())) {
+                    continue;
+                }
+                if (route.matches(dest)) bestRoute = route;
+            }
+        }
+        return bestRoute;
+    }
+
     public String toString() {
         String val = "";
         if (mDestination != null) val = mDestination.toString();
@@ -185,10 +302,37 @@
         return val;
     }
 
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+
+        if (!(obj instanceof RouteInfo)) return false;
+
+        RouteInfo target = (RouteInfo) obj;
+
+        return Objects.equals(mDestination, target.getDestination()) &&
+                Objects.equals(mGateway, target.getGateway()) &&
+                Objects.equals(mInterface, target.getInterface());
+    }
+
+    public int hashCode() {
+        return (mDestination == null ? 0 : mDestination.hashCode() * 41)
+                + (mGateway == null ? 0 :mGateway.hashCode() * 47)
+                + (mInterface == null ? 0 :mInterface.hashCode() * 67)
+                + (mIsDefault ? 3 : 7);
+    }
+
+    /**
+     * Implement the Parcelable interface
+     * @hide
+     */
     public int describeContents() {
         return 0;
     }
 
+    /**
+     * Implement the Parcelable interface
+     * @hide
+     */
     public void writeToParcel(Parcel dest, int flags) {
         if (mDestination == null) {
             dest.writeByte((byte) 0);
@@ -208,38 +352,10 @@
         dest.writeString(mInterface);
     }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-
-        if (!(obj instanceof RouteInfo)) return false;
-
-        RouteInfo target = (RouteInfo) obj;
-
-        boolean sameDestination = ( mDestination == null) ?
-                target.getDestination() == null
-                : mDestination.equals(target.getDestination());
-
-        boolean sameAddress = (mGateway == null) ?
-                target.getGateway() == null
-                : mGateway.equals(target.getGateway());
-
-        boolean sameInterface = (mInterface == null) ?
-                target.getInterface() == null
-                : mInterface.equals(target.getInterface());
-
-        return sameDestination && sameAddress && sameInterface
-            && mIsDefault == target.mIsDefault;
-    }
-
-    @Override
-    public int hashCode() {
-        return (mDestination == null ? 0 : mDestination.hashCode() * 41)
-            + (mGateway == null ? 0 :mGateway.hashCode() * 47)
-            + (mInterface == null ? 0 :mInterface.hashCode() * 67)
-            + (mIsDefault ? 3 : 7);
-    }
-
+    /**
+     * Implement the Parcelable interface.
+     * @hide
+     */
     public static final Creator<RouteInfo> CREATOR =
         new Creator<RouteInfo>() {
         public RouteInfo createFromParcel(Parcel in) {
@@ -279,39 +395,4 @@
             return new RouteInfo[size];
         }
     };
-
-    protected boolean matches(InetAddress destination) {
-        if (destination == null) return false;
-
-        // match the route destination and destination with prefix length
-        InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
-                mDestination.getNetworkPrefixLength());
-
-        return mDestination.getAddress().equals(dstNet);
-    }
-
-    /**
-     * Find the route from a Collection of routes that best matches a given address.
-     * May return null if no routes are applicable.
-     * @param routes a Collection of RouteInfos to chose from
-     * @param dest the InetAddress your trying to get to
-     * @return the RouteInfo from the Collection that best fits the given address
-     */
-    public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
-        if ((routes == null) || (dest == null)) return null;
-
-        RouteInfo bestRoute = null;
-        // pick a longest prefix match under same address type
-        for (RouteInfo route : routes) {
-            if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) {
-                if ((bestRoute != null) &&
-                        (bestRoute.mDestination.getNetworkPrefixLength() >=
-                        route.mDestination.getNetworkPrefixLength())) {
-                    continue;
-                }
-                if (route.matches(dest)) bestRoute = route;
-            }
-        }
-        return bestRoute;
-    }
 }
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/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index 5c8c8e9..ad940c6 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -621,8 +621,9 @@
      * Registers a listener.
      * 
      * @see OnActivityStopListener
+     * @hide
      */
-    void registerOnActivityStopListener(OnActivityStopListener listener) {
+    public void registerOnActivityStopListener(OnActivityStopListener listener) {
         synchronized (this) {
             if (mActivityStopListeners == null) {
                 mActivityStopListeners = new ArrayList<OnActivityStopListener>();
@@ -638,8 +639,9 @@
      * Unregisters a listener.
      * 
      * @see OnActivityStopListener
+     * @hide
      */
-    void unregisterOnActivityStopListener(OnActivityStopListener listener) {
+    public void unregisterOnActivityStopListener(OnActivityStopListener listener) {
         synchronized (this) {
             if (mActivityStopListeners != null) {
                 mActivityStopListeners.remove(listener);
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
new file mode 100644
index 0000000..d2d6ade
--- /dev/null
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -0,0 +1,248 @@
+/*
+ * 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.preference;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.media.AudioManager;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.preference.VolumePreference.VolumeStore;
+import android.provider.Settings;
+import android.provider.Settings.System;
+import android.util.Log;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+
+/**
+ * Turns a {@link SeekBar} into a volume control.
+ * @hide
+ */
+public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callback {
+
+    public interface Callback {
+        void onSampleStarting(SeekBarVolumizer sbv);
+    }
+
+    private Context mContext;
+    private Handler mHandler;
+    private final Callback mCallback;
+
+    private AudioManager mAudioManager;
+    private int mStreamType;
+    private int mOriginalStreamVolume;
+    private Ringtone mRingtone;
+
+    private int mLastProgress = -1;
+    private SeekBar mSeekBar;
+    private int mVolumeBeforeMute = -1;
+
+    private static final int MSG_SET_STREAM_VOLUME = 0;
+    private static final int MSG_START_SAMPLE = 1;
+    private static final int MSG_STOP_SAMPLE = 2;
+    private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000;
+
+    private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
+        @Override
+        public void onChange(boolean selfChange) {
+            super.onChange(selfChange);
+            if (mSeekBar != null && mAudioManager != null) {
+                int volume = mAudioManager.getStreamVolume(mStreamType);
+                mSeekBar.setProgress(volume);
+            }
+        }
+    };
+
+    public SeekBarVolumizer(Context context, SeekBar seekBar, int streamType, Uri defaultUri,
+            Callback callback) {
+        mContext = context;
+        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        mStreamType = streamType;
+        mSeekBar = seekBar;
+
+        HandlerThread thread = new HandlerThread(VolumePreference.TAG + ".CallbackHandler");
+        thread.start();
+        mHandler = new Handler(thread.getLooper(), this);
+        mCallback = callback;
+
+        initSeekBar(seekBar, defaultUri);
+    }
+
+    private void initSeekBar(SeekBar seekBar, Uri defaultUri) {
+        seekBar.setMax(mAudioManager.getStreamMaxVolume(mStreamType));
+        mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
+        seekBar.setProgress(mOriginalStreamVolume);
+        seekBar.setOnSeekBarChangeListener(this);
+
+        mContext.getContentResolver().registerContentObserver(
+                System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
+                false, mVolumeObserver);
+
+        if (defaultUri == null) {
+            if (mStreamType == AudioManager.STREAM_RING) {
+                defaultUri = Settings.System.DEFAULT_RINGTONE_URI;
+            } else if (mStreamType == AudioManager.STREAM_NOTIFICATION) {
+                defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;
+            } else {
+                defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI;
+            }
+        }
+
+        mRingtone = RingtoneManager.getRingtone(mContext, defaultUri);
+
+        if (mRingtone != null) {
+            mRingtone.setStreamType(mStreamType);
+        }
+    }
+
+    @Override
+    public boolean handleMessage(Message msg) {
+        switch (msg.what) {
+            case MSG_SET_STREAM_VOLUME:
+                mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0);
+                break;
+            case MSG_START_SAMPLE:
+                onStartSample();
+                break;
+            case MSG_STOP_SAMPLE:
+                onStopSample();
+                break;
+            default:
+                Log.e(VolumePreference.TAG, "invalid SeekBarVolumizer message: "+msg.what);
+        }
+        return true;
+    }
+
+    private void postStartSample() {
+        mHandler.removeMessages(MSG_START_SAMPLE);
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE),
+                isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0);
+    }
+
+    private void onStartSample() {
+        if (!isSamplePlaying()) {
+            if (mCallback != null) {
+                mCallback.onSampleStarting(this);
+            }
+            if (mRingtone != null) {
+                mRingtone.play();
+            }
+        }
+    }
+
+    void postStopSample() {
+        // remove pending delayed start messages
+        mHandler.removeMessages(MSG_START_SAMPLE);
+        mHandler.removeMessages(MSG_STOP_SAMPLE);
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_STOP_SAMPLE));
+    }
+
+    private void onStopSample() {
+        if (mRingtone != null) {
+            mRingtone.stop();
+        }
+    }
+
+    public void stop() {
+        postStopSample();
+        mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
+        mSeekBar.setOnSeekBarChangeListener(null);
+    }
+
+    public void revertVolume() {
+        mAudioManager.setStreamVolume(mStreamType, mOriginalStreamVolume, 0);
+    }
+
+    public void onProgressChanged(SeekBar seekBar, int progress,
+            boolean fromTouch) {
+        if (!fromTouch) {
+            return;
+        }
+
+        postSetVolume(progress);
+    }
+
+    void postSetVolume(int progress) {
+        // Do the volume changing separately to give responsive UI
+        mLastProgress = progress;
+        mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME));
+    }
+
+    public void onStartTrackingTouch(SeekBar seekBar) {
+    }
+
+    public void onStopTrackingTouch(SeekBar seekBar) {
+        postStartSample();
+    }
+
+    public boolean isSamplePlaying() {
+        return mRingtone != null && mRingtone.isPlaying();
+    }
+
+    public void startSample() {
+        postStartSample();
+    }
+
+    public void stopSample() {
+        postStopSample();
+    }
+
+    public SeekBar getSeekBar() {
+        return mSeekBar;
+    }
+
+    public void changeVolumeBy(int amount) {
+        mSeekBar.incrementProgressBy(amount);
+        postSetVolume(mSeekBar.getProgress());
+        postStartSample();
+        mVolumeBeforeMute = -1;
+    }
+
+    public void muteVolume() {
+        if (mVolumeBeforeMute != -1) {
+            mSeekBar.setProgress(mVolumeBeforeMute);
+            postSetVolume(mVolumeBeforeMute);
+            postStartSample();
+            mVolumeBeforeMute = -1;
+        } else {
+            mVolumeBeforeMute = mSeekBar.getProgress();
+            mSeekBar.setProgress(0);
+            postStopSample();
+            postSetVolume(0);
+        }
+    }
+
+    public void onSaveInstanceState(VolumeStore volumeStore) {
+        if (mLastProgress >= 0) {
+            volumeStore.volume = mLastProgress;
+            volumeStore.originalVolume = mOriginalStreamVolume;
+        }
+    }
+
+    public void onRestoreInstanceState(VolumeStore volumeStore) {
+        if (volumeStore.volume != -1) {
+            mOriginalStreamVolume = volumeStore.originalVolume;
+            mLastProgress = volumeStore.volume;
+            postSetVolume(mLastProgress);
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 29f2545..171e5c3 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -19,32 +19,20 @@
 import android.app.Dialog;
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.database.ContentObserver;
-import android.media.AudioManager;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Message;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.provider.Settings;
-import android.provider.Settings.System;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
 import android.widget.SeekBar;
-import android.widget.SeekBar.OnSeekBarChangeListener;
 
 /**
  * @hide
  */
 public class VolumePreference extends SeekBarDialogPreference implements
-        PreferenceManager.OnActivityStopListener, View.OnKeyListener {
+        PreferenceManager.OnActivityStopListener, View.OnKeyListener, SeekBarVolumizer.Callback {
 
-    private static final String TAG = "VolumePreference";
+    static final String TAG = "VolumePreference";
 
     private int mStreamType;
 
@@ -66,7 +54,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) {
@@ -78,7 +66,7 @@
         super.onBindDialogView(view);
 
         final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
-        mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType);
+        mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType, null, this);
 
         getPreferenceManager().registerOnActivityStopListener(this);
 
@@ -152,7 +140,8 @@
 
     }
 
-    protected void onSampleStarting(SeekBarVolumizer volumizer) {
+    @Override
+    public void onSampleStarting(SeekBarVolumizer volumizer) {
         if (mSeekBarVolumizer != null && volumizer != mSeekBarVolumizer) {
             mSeekBarVolumizer.stopSample();
         }
@@ -228,213 +217,4 @@
             }
         };
     }
-
-    /**
-     * Turns a {@link SeekBar} into a volume control.
-     */
-    public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callback {
-
-        private Context mContext;
-        private Handler mHandler;
-
-        private AudioManager mAudioManager;
-        private int mStreamType;
-        private int mOriginalStreamVolume;
-        private Ringtone mRingtone;
-
-        private int mLastProgress = -1;
-        private SeekBar mSeekBar;
-        private int mVolumeBeforeMute = -1;
-
-        private static final int MSG_SET_STREAM_VOLUME = 0;
-        private static final int MSG_START_SAMPLE = 1;
-        private static final int MSG_STOP_SAMPLE = 2;
-        private static final int CHECK_RINGTONE_PLAYBACK_DELAY_MS = 1000;
-
-        private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
-            @Override
-            public void onChange(boolean selfChange) {
-                super.onChange(selfChange);
-                if (mSeekBar != null && mAudioManager != null) {
-                    int volume = mAudioManager.getStreamVolume(mStreamType);
-                    mSeekBar.setProgress(volume);
-                }
-            }
-        };
-
-        public SeekBarVolumizer(Context context, SeekBar seekBar, int streamType) {
-            this(context, seekBar, streamType, null);
-        }
-
-        public SeekBarVolumizer(Context context, SeekBar seekBar, int streamType, Uri defaultUri) {
-            mContext = context;
-            mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-            mStreamType = streamType;
-            mSeekBar = seekBar;
-
-            HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler");
-            thread.start();
-            mHandler = new Handler(thread.getLooper(), this);
-
-            initSeekBar(seekBar, defaultUri);
-        }
-
-        private void initSeekBar(SeekBar seekBar, Uri defaultUri) {
-            seekBar.setMax(mAudioManager.getStreamMaxVolume(mStreamType));
-            mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
-            seekBar.setProgress(mOriginalStreamVolume);
-            seekBar.setOnSeekBarChangeListener(this);
-
-            mContext.getContentResolver().registerContentObserver(
-                    System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
-                    false, mVolumeObserver);
-
-            if (defaultUri == null) {
-                if (mStreamType == AudioManager.STREAM_RING) {
-                    defaultUri = Settings.System.DEFAULT_RINGTONE_URI;
-                } else if (mStreamType == AudioManager.STREAM_NOTIFICATION) {
-                    defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;
-                } else {
-                    defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI;
-                }
-            }
-
-            mRingtone = RingtoneManager.getRingtone(mContext, defaultUri);
-
-            if (mRingtone != null) {
-                mRingtone.setStreamType(mStreamType);
-            }
-        }
-
-        @Override
-        public boolean handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_SET_STREAM_VOLUME:
-                    mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0);
-                    break;
-                case MSG_START_SAMPLE:
-                    onStartSample();
-                    break;
-                case MSG_STOP_SAMPLE:
-                    onStopSample();
-                    break;
-                default:
-                    Log.e(TAG, "invalid SeekBarVolumizer message: "+msg.what);
-            }
-            return true;
-        }
-
-        private void postStartSample() {
-            mHandler.removeMessages(MSG_START_SAMPLE);
-            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE),
-                    isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0);
-        }
-
-        private void onStartSample() {
-            if (!isSamplePlaying()) {
-                onSampleStarting(this);
-                if (mRingtone != null) {
-                    mRingtone.play();
-                }
-            }
-        }
-
-        private void postStopSample() {
-            // remove pending delayed start messages
-            mHandler.removeMessages(MSG_START_SAMPLE);
-            mHandler.removeMessages(MSG_STOP_SAMPLE);
-            mHandler.sendMessage(mHandler.obtainMessage(MSG_STOP_SAMPLE));
-        }
-
-        private void onStopSample() {
-            if (mRingtone != null) {
-                mRingtone.stop();
-            }
-        }
-
-        public void stop() {
-            postStopSample();
-            mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
-            mSeekBar.setOnSeekBarChangeListener(null);
-        }
-
-        public void revertVolume() {
-            mAudioManager.setStreamVolume(mStreamType, mOriginalStreamVolume, 0);
-        }
-
-        public void onProgressChanged(SeekBar seekBar, int progress,
-                boolean fromTouch) {
-            if (!fromTouch) {
-                return;
-            }
-
-            postSetVolume(progress);
-        }
-
-        void postSetVolume(int progress) {
-            // Do the volume changing separately to give responsive UI
-            mLastProgress = progress;
-            mHandler.removeMessages(MSG_SET_STREAM_VOLUME);
-            mHandler.sendMessage(mHandler.obtainMessage(MSG_SET_STREAM_VOLUME));
-        }
-
-        public void onStartTrackingTouch(SeekBar seekBar) {
-        }
-
-        public void onStopTrackingTouch(SeekBar seekBar) {
-            postStartSample();
-        }
-
-        public boolean isSamplePlaying() {
-            return mRingtone != null && mRingtone.isPlaying();
-        }
-
-        public void startSample() {
-            postStartSample();
-        }
-
-        public void stopSample() {
-            postStopSample();
-        }
-
-        public SeekBar getSeekBar() {
-            return mSeekBar;
-        }
-
-        public void changeVolumeBy(int amount) {
-            mSeekBar.incrementProgressBy(amount);
-            postSetVolume(mSeekBar.getProgress());
-            postStartSample();
-            mVolumeBeforeMute = -1;
-        }
-
-        public void muteVolume() {
-            if (mVolumeBeforeMute != -1) {
-                mSeekBar.setProgress(mVolumeBeforeMute);
-                postSetVolume(mVolumeBeforeMute);
-                postStartSample();
-                mVolumeBeforeMute = -1;
-            } else {
-                mVolumeBeforeMute = mSeekBar.getProgress();
-                mSeekBar.setProgress(0);
-                postStopSample();
-                postSetVolume(0);
-            }
-        }
-
-        public void onSaveInstanceState(VolumeStore volumeStore) {
-            if (mLastProgress >= 0) {
-                volumeStore.volume = mLastProgress;
-                volumeStore.originalVolume = mOriginalStreamVolume;
-            }
-        }
-
-        public void onRestoreInstanceState(VolumeStore volumeStore) {
-            if (volumeStore.volume != -1) {
-                mOriginalStreamVolume = volumeStore.originalVolume;
-                mLastProgress = volumeStore.volume;
-                postSetVolume(mLastProgress);
-            }
-        }
-    }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 89f4388..e896063 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 */
@@ -4533,6 +4556,12 @@
         public static final String PAYMENT_SERVICE_SEARCH_URI = "payment_service_search_uri";
 
         /**
+         * If enabled, intercepted notifications will be displayed (not suppressed) in zen mode.
+         * @hide
+         */
+        public static final String DISPLAY_INTERCEPTED_NOTIFICATIONS = "display_intercepted_notifications";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -5319,6 +5348,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..98f70f4 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -16,12 +16,17 @@
 
 package android.service.trust;
 
+import android.Manifest;
 import android.annotation.SdkConstant;
 import android.app.Service;
+import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.util.Log;
 import android.util.Slog;
 
 /**
@@ -29,12 +34,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 +52,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 {
@@ -83,12 +88,28 @@
         };
     };
 
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        ComponentName component = new ComponentName(this, getClass());
+        try {
+            ServiceInfo serviceInfo = getPackageManager().getServiceInfo(component, 0 /* flags */);
+            if (!Manifest.permission.BIND_TRUST_AGENT.equals(serviceInfo.permission)) {
+                throw new IllegalStateException(component.flattenToShortString()
+                        + " is not declared with the permission "
+                        + "\"" + Manifest.permission.BIND_TRUST_AGENT + "\"");
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, "Can't get ServiceInfo for " + component.toShortString());
+        }
+    }
+
     /**
      * Called when the user attempted to authenticate on the device.
      *
      * @param successful true if the attempt succeeded
      */
-    protected void onUnlockAttempt(boolean successful) {
+    public void onUnlockAttempt(boolean successful) {
     }
 
     private void onError(String msg) {
@@ -96,7 +117,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 +125,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 +138,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/speech/tts/TextToSpeechClient.java b/core/java/android/speech/tts/TextToSpeechClient.java
index 10e2073..85f702b 100644
--- a/core/java/android/speech/tts/TextToSpeechClient.java
+++ b/core/java/android/speech/tts/TextToSpeechClient.java
@@ -25,7 +25,10 @@
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.speech.tts.ITextToSpeechCallback;
@@ -86,6 +89,8 @@
     private HashMap<String, Pair<UtteranceId, RequestCallbacks>> mCallbacks;
     // Guarded by mLock
 
+    private InternalHandler mMainHandler = new InternalHandler();
+
     /** Common voices parameters */
     public static final class Params {
         private Params() {}
@@ -300,6 +305,8 @@
     /**
      * Interface definition of callbacks that are called when the client is
      * connected or disconnected from the TTS service.
+     *
+     * The callbacks specified in this method will be called on the UI thread.
      */
     public static interface ConnectionCallbacks {
         /**
@@ -325,6 +332,9 @@
          * with the speech service (e.g. a crash or resource problem causes it to be killed by the
          * system). When called, all requests have been canceled and no outstanding listeners will
          * be executed. Applications should disable UI components that require the service.
+         *
+         * When the service is working again, the client will receive a callback to the
+         * {@link #onConnectionSuccess()} method.
          */
         public void onServiceDisconnected();
 
@@ -688,7 +698,8 @@
                 synchronized (mLock) {
                     mEngineStatus = new EngineStatus(mServiceConnection.getEngineName(),
                             voicesInfo);
-                    mConnectionCallbacks.onEngineStatusChange(mEngineStatus);
+                    mMainHandler.obtainMessage(InternalHandler.WHAT_ENGINE_STATUS_CHANGED,
+                            mEngineStatus).sendToTarget();
                 }
             }
         };
@@ -753,9 +764,11 @@
             Log.i(TAG, "Asked to disconnect from " + name);
 
             synchronized(mLock) {
+                mEstablished = false;
+                mService = null;
                 stopSetupConnectionTask();
             }
-            mConnectionCallbacks.onServiceDisconnected();
+            mMainHandler.obtainMessage(InternalHandler.WHAT_SERVICE_DISCONNECTED).sendToTarget();
         }
 
         private void startSetupConnectionTask(ComponentName name) {
@@ -830,9 +843,11 @@
     private boolean runAction(Action action) {
         synchronized (mLock) {
             if (mServiceConnection == null) {
+                Log.w(TAG, action.getName() + " failed: not bound to TTS engine");
                 return false;
             }
             if (!mServiceConnection.isEstablished()) {
+                Log.w(TAG, action.getName() + " failed: not fully bound to TTS engine");
                 return false;
             }
             mServiceConnection.runAction(action);
@@ -1044,4 +1059,21 @@
             }
         });
     }
+
+    class InternalHandler extends Handler {
+        final static int WHAT_ENGINE_STATUS_CHANGED = 1;
+        final static int WHAT_SERVICE_DISCONNECTED = 2;
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case WHAT_ENGINE_STATUS_CHANGED:
+                    mConnectionCallbacks.onEngineStatusChange((EngineStatus) msg.obj);
+                    return;
+                case WHAT_SERVICE_DISCONNECTED:
+                    mConnectionCallbacks.onServiceDisconnected();
+                    return;
+            }
+        }
+    }
 }
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index d7c51fc..6b899d9 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -255,7 +255,8 @@
         // V2 to V1 interface adapter. This allows using V2 client interface on V1-only services.
         Bundle defaultParams = new Bundle();
         defaultParams.putFloat(TextToSpeechClient.Params.SPEECH_PITCH, 1.0f);
-        defaultParams.putFloat(TextToSpeechClient.Params.SPEECH_SPEED, -1.0f);
+        // Speech speed <= 0 makes it use a system wide setting
+        defaultParams.putFloat(TextToSpeechClient.Params.SPEECH_SPEED, 0.0f);
 
         // Enumerate all locales and check if they are available
         ArrayList<VoiceInfo> voicesInfo = new ArrayList<VoiceInfo>();
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/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 17035b1..74972c2 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -193,7 +193,7 @@
         Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList");
         HardwareCanvas canvas = mRootNode.start(mWidth, mHeight);
         try {
-            callbacks.onHardwarePostDraw(canvas);
+            callbacks.onHardwarePreDraw(canvas);
             canvas.drawDisplayList(view.getDisplayList());
             callbacks.onHardwarePostDraw(canvas);
         } finally {
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..eed6412 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -111,6 +111,7 @@
     private static final boolean DEBUG_IMF = false || LOCAL_LOGV;
     private static final boolean DEBUG_CONFIGURATION = false || LOCAL_LOGV;
     private static final boolean DEBUG_FPS = false;
+    private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
 
     /**
      * Set this system property to true to force the view hierarchy to render
@@ -668,6 +669,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) {
@@ -3481,6 +3487,9 @@
          * Called when an event is being delivered to the next stage.
          */
         protected void onDeliverToNext(QueuedInputEvent q) {
+            if (DEBUG_INPUT_STAGES) {
+                Log.v(TAG, "Done with " + getClass().getSimpleName() + ". " + q);
+            }
             if (mNext != null) {
                 mNext.deliver(q);
             } else {
@@ -5515,6 +5524,37 @@
 
             return false;
         }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder("QueuedInputEvent{flags=");
+            boolean hasPrevious = false;
+            hasPrevious = flagToString("DELIVER_POST_IME", FLAG_DELIVER_POST_IME, hasPrevious, sb);
+            hasPrevious = flagToString("DEFERRED", FLAG_DEFERRED, hasPrevious, sb);
+            hasPrevious = flagToString("FINISHED", FLAG_FINISHED, hasPrevious, sb);
+            hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
+            hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
+            hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
+            if (!hasPrevious) {
+                sb.append("0");
+            }
+            sb.append(", hasNextQueuedEvent=" + (mEvent != null ? "true" : "false"));
+            sb.append(", hasInputEventReceiver=" + (mReceiver != null ? "true" : "false"));
+            sb.append(", mEvent=" + mEvent + "}");
+            return sb.toString();
+        }
+
+        private boolean flagToString(String name, int flag,
+                boolean hasPrevious, StringBuilder sb) {
+            if ((mFlags & flag) != 0) {
+                if (hasPrevious) {
+                    sb.append("|");
+                }
+                sb.append(name);
+                return true;
+            }
+            return hasPrevious;
+        }
     }
 
     private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
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/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index ac12357..aaf0a75 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -30,6 +30,9 @@
     private static final String CHROMIUM_WEBVIEW_FACTORY =
             "com.android.webview.chromium.WebViewChromiumFactoryProvider";
 
+    private static final String NULL_WEBVIEW_FACTORY =
+            "com.android.webview.nullwebview.NullWebViewFactoryProvider";
+
     private static final String LOGTAG = "WebViewFactory";
 
     private static final boolean DEBUG = false;
@@ -88,6 +91,11 @@
     }
 
     private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException {
-        return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY);
+        try {
+            return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY);
+        } catch (ClassNotFoundException e) {
+            Log.e(LOGTAG, "Chromium WebView does not exist");
+            return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
+        }
     }
 }
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..a238ae3 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -183,7 +183,7 @@
 
     private void init(View decor) {
         mOverlayLayout = (ActionBarOverlayLayout) decor.findViewById(
-                com.android.internal.R.id.action_bar_overlay_layout);
+                com.android.internal.R.id.decor_content_parent);
         if (mOverlayLayout != null) {
             mOverlayLayout.setActionBarVisibilityCallback(this);
         }
@@ -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/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index 4b84941..81e67d8 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -48,6 +48,8 @@
     public static final int BASE_WIFI_CONTROLLER                                    = 0x00026000;
     public static final int BASE_WIFI_SCANNER                                       = 0x00027000;
     public static final int BASE_WIFI_SCANNER_SERVICE                               = 0x00027100;
+    public static final int BASE_WIFI_PASSPOINT_MANAGER                             = 0x00028000;
+    public static final int BASE_WIFI_PASSPOINT_SERVICE                             = 0x00028100;
     public static final int BASE_DHCP                                               = 0x00030000;
     public static final int BASE_DATA_CONNECTION                                    = 0x00040000;
     public static final int BASE_DATA_CONNECTION_AC                                 = 0x00041000;
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/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 19d58bf..7ab4bed 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -19,26 +19,34 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
+import android.content.pm.ActivityInfo;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.IntProperty;
+import android.util.Log;
 import android.util.Property;
+import android.util.SparseArray;
+import android.view.KeyEvent;
+import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewPropertyAnimator;
+import android.view.Window;
 import android.view.WindowInsets;
 import android.widget.OverScroller;
+import com.android.internal.view.menu.MenuPresenter;
 
 /**
  * Special layout for the containing of an overlay action bar (and its
  * content) to correctly handle fitting system windows when the content
  * has request that its layout ignore them.
  */
-public class ActionBarOverlayLayout extends ViewGroup {
+public class ActionBarOverlayLayout extends ViewGroup implements DecorContentParent {
     private static final String TAG = "ActionBarOverlayLayout";
 
     private int mActionBarHeight;
@@ -47,7 +55,7 @@
 
     // The main UI elements that we handle the layout of.
     private View mContent;
-    private View mActionBarBottom;
+    private ActionBarContainer mActionBarBottom;
     private ActionBarContainer mActionBarTop;
 
     // Some interior UI elements.
@@ -556,7 +564,8 @@
             mActionBarTop = (ActionBarContainer) findViewById(
                     com.android.internal.R.id.action_bar_container);
             mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
-            mActionBarBottom = findViewById(com.android.internal.R.id.split_action_bar);
+            mActionBarBottom = (ActionBarContainer) findViewById(
+                    com.android.internal.R.id.split_action_bar);
         }
     }
 
@@ -629,6 +638,179 @@
         return finalY > mActionBarTop.getHeight();
     }
 
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (super.dispatchKeyEvent(event)) {
+            return true;
+        }
+
+        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+            final int action = event.getAction();
+
+            // Collapse any expanded action views.
+            if (mActionBarView != null && mActionBarView.hasExpandedActionView()) {
+                if (action == KeyEvent.ACTION_UP) {
+                    mActionBarView.collapseActionView();
+                }
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public void setWindowCallback(Window.Callback cb) {
+        pullChildren();
+        mActionBarView.setWindowCallback(cb);
+    }
+
+    @Override
+    public void setWindowTitle(CharSequence title) {
+        pullChildren();
+        mActionBarView.setWindowTitle(title);
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        pullChildren();
+        return mActionBarView.getTitle();
+    }
+
+    @Override
+    public void initFeature(int windowFeature) {
+        pullChildren();
+        switch (windowFeature) {
+            case Window.FEATURE_PROGRESS:
+                mActionBarView.initProgress();
+                break;
+            case Window.FEATURE_INDETERMINATE_PROGRESS:
+                mActionBarView.initIndeterminateProgress();
+                break;
+            case Window.FEATURE_ACTION_BAR_OVERLAY:
+                setOverlayMode(true);
+                break;
+        }
+    }
+
+    @Override
+    public void setUiOptions(int uiOptions) {
+        boolean splitActionBar = false;
+        final boolean splitWhenNarrow =
+                (uiOptions & ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW) != 0;
+        if (splitWhenNarrow) {
+            splitActionBar = getContext().getResources().getBoolean(
+                    com.android.internal.R.bool.split_action_bar_is_narrow);
+        }
+        if (splitActionBar) {
+            pullChildren();
+            if (mActionBarBottom != null) {
+                mActionBarView.setSplitView(mActionBarBottom);
+                mActionBarView.setSplitActionBar(splitActionBar);
+                mActionBarView.setSplitWhenNarrow(splitWhenNarrow);
+
+                final ActionBarContextView cab = (ActionBarContextView) findViewById(
+                        com.android.internal.R.id.action_context_bar);
+                cab.setSplitView(mActionBarBottom);
+                cab.setSplitActionBar(splitActionBar);
+                cab.setSplitWhenNarrow(splitWhenNarrow);
+            } else if (splitActionBar) {
+                Log.e(TAG, "Requested split action bar with " +
+                        "incompatible window decor! Ignoring request.");
+            }
+        }
+    }
+
+    @Override
+    public boolean hasIcon() {
+        pullChildren();
+        return mActionBarView.hasIcon();
+    }
+
+    @Override
+    public boolean hasLogo() {
+        pullChildren();
+        return mActionBarView.hasLogo();
+    }
+
+    @Override
+    public void setIcon(int resId) {
+        pullChildren();
+        mActionBarView.setIcon(resId);
+    }
+
+    @Override
+    public void setIcon(Drawable d) {
+        pullChildren();
+        mActionBarView.setIcon(d);
+    }
+
+    @Override
+    public void setLogo(int resId) {
+        pullChildren();
+        mActionBarView.setLogo(resId);
+    }
+
+    @Override
+    public boolean canShowOverflowMenu() {
+        pullChildren();
+        return mActionBarView.isOverflowReserved() && mActionBarView.getVisibility() == VISIBLE;
+    }
+
+    @Override
+    public boolean isOverflowMenuShowing() {
+        pullChildren();
+        return mActionBarView.isOverflowMenuShowing();
+    }
+
+    @Override
+    public boolean isOverflowMenuShowPending() {
+        pullChildren();
+        return mActionBarView.isOverflowMenuShowPending();
+    }
+
+    @Override
+    public boolean showOverflowMenu() {
+        pullChildren();
+        return mActionBarView.showOverflowMenu();
+    }
+
+    @Override
+    public boolean hideOverflowMenu() {
+        pullChildren();
+        return mActionBarView.hideOverflowMenu();
+    }
+
+    @Override
+    public void setMenuPrepared() {
+        pullChildren();
+        mActionBarView.setMenuPrepared();
+    }
+
+    @Override
+    public void setMenu(Menu menu, MenuPresenter.Callback cb) {
+        pullChildren();
+        mActionBarView.setMenu(menu, cb);
+    }
+
+    @Override
+    public void saveToolbarHierarchyState(SparseArray<Parcelable> toolbarStates) {
+        pullChildren();
+        mActionBarView.saveHierarchyState(toolbarStates);
+    }
+
+    @Override
+    public void restoreToolbarHierarchyState(SparseArray<Parcelable> toolbarStates) {
+        pullChildren();
+        mActionBarView.restoreHierarchyState(toolbarStates);
+    }
+
+    @Override
+    public void dismissPopups() {
+        pullChildren();
+        mActionBarView.dismissPopupMenus();
+    }
+
     public static class LayoutParams extends MarginLayoutParams {
         public LayoutParams(Context c, AttributeSet attrs) {
             super(c, attrs);
diff --git a/core/java/com/android/internal/widget/DecorContentParent.java b/core/java/com/android/internal/widget/DecorContentParent.java
new file mode 100644
index 0000000..4fa370a
--- /dev/null
+++ b/core/java/com/android/internal/widget/DecorContentParent.java
@@ -0,0 +1,53 @@
+/*
+ * 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.internal.widget;
+
+import android.graphics.drawable.Drawable;
+import android.os.Parcelable;
+import android.util.SparseArray;
+import android.view.Menu;
+import android.view.Window;
+import com.android.internal.view.menu.MenuPresenter;
+
+/**
+ * Implemented by the top-level decor layout for a window. DecorContentParent offers
+ * entry points for a number of title/window decor features.
+ */
+public interface DecorContentParent {
+    void setWindowCallback(Window.Callback cb);
+    void setWindowTitle(CharSequence title);
+    CharSequence getTitle();
+    void initFeature(int windowFeature);
+    void setUiOptions(int uiOptions);
+    boolean hasIcon();
+    boolean hasLogo();
+    void setIcon(int resId);
+    void setIcon(Drawable d);
+    void setLogo(int resId);
+    boolean canShowOverflowMenu();
+    boolean isOverflowMenuShowing();
+    boolean isOverflowMenuShowPending();
+    boolean showOverflowMenu();
+    boolean hideOverflowMenu();
+    void setMenuPrepared();
+    void setMenu(Menu menu, MenuPresenter.Callback cb);
+    void saveToolbarHierarchyState(SparseArray<Parcelable> toolbarStates);
+    void restoreToolbarHierarchyState(SparseArray<Parcelable> toolbarStates);
+    void dismissPopups();
+
+}
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..99bbe39 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,8 @@
 	libharfbuzz_ng \
 	libz \
 	libaudioutils \
+	libpdfrenderer \
+	libimg_utils \
 
 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_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index fa2cfe3..3312109 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -30,6 +30,7 @@
 #include "JNIHelp.h"
 #include "android_os_Parcel.h"
 #include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
 
 #include <binder/IServiceManager.h>
 #include <camera/CameraMetadata.h>
@@ -57,6 +58,31 @@
 
 static fields_t fields;
 
+namespace android {
+
+status_t CameraMetadata_getNativeMetadata(JNIEnv* env, jobject thiz,
+        /*out*/CameraMetadata* metadata) {
+    if (!thiz) {
+        ALOGE("%s: Invalid java metadata object.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    if (!metadata) {
+        ALOGE("%s: Invalid output metadata object.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    CameraMetadata* nativePtr = reinterpret_cast<CameraMetadata*>(env->GetLongField(thiz,
+            fields.metadata_ptr));
+    if (nativePtr == NULL) {
+        ALOGE("%s: Invalid native pointer in java metadata object.", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    *metadata = *nativePtr;
+    return OK;
+}
+
+} /*namespace android*/
+
 namespace {
 struct Helpers {
     static size_t getTypeSize(uint8_t type) {
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-xlarge/screen_action_bar.xml b/core/res/res/layout-xlarge/screen_action_bar.xml
deleted file mode 100644
index 02c99fe..0000000
--- a/core/res/res/layout-xlarge/screen_action_bar.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<!--
-This is an optimized layout for a screen with
-the Action Bar enabled overlaying application content.
--->
-
-<com.android.internal.widget.ActionBarOverlayLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/action_bar_overlay_layout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:splitMotionEvents="false">
-    <FrameLayout android:id="@android:id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-    <com.android.internal.widget.ActionBarContainer
-        android:id="@+id/action_bar_container"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_alignParentTop="true"
-        style="?android:attr/actionBarStyle"
-        android:viewName="android:action_bar"
-        android:gravity="top">
-        <com.android.internal.widget.ActionBarView
-            android:id="@+id/action_bar"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            style="?android:attr/actionBarStyle" />
-        <com.android.internal.widget.ActionBarContextView
-            android:id="@+id/action_context_bar"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:visibility="gone"
-            style="?android:attr/actionModeStyle" />
-    </com.android.internal.widget.ActionBarContainer>
-</com.android.internal.widget.ActionBarOverlayLayout>
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/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
index eb237b3..8bf8416 100644
--- a/core/res/res/layout/screen_action_bar.xml
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -20,7 +20,7 @@
 
 <com.android.internal.widget.ActionBarOverlayLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/action_bar_overlay_layout"
+    android:id="@+id/decor_content_parent"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:splitMotionEvents="false"
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..9fba1bf 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -355,10 +355,6 @@
              when there is not reserved space for their UI (such as an Action Bar). -->
         <attr name="windowActionModeOverlay" format="boolean" />
 
-        <!-- Flag indicating that the action bar should be split to provide more
-             room for elements. -->
-        <attr name="windowSplitActionBar" format="boolean" />
-
         <!-- Defines the default soft input state that this window would
              like when it is displayed.  Corresponds
              to {@link android.view.WindowManager.LayoutParams#softInputMode}. -->
@@ -657,7 +653,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 +1668,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>
 
     <!-- ***************************************************************** -->
@@ -1702,7 +1701,6 @@
         <attr name="windowActionBar" />
         <attr name="windowActionModeOverlay" />
         <attr name="windowActionBarOverlay" />
-        <attr name="windowSplitActionBar" />
         <attr name="windowEnableSplitTouch" />
         <attr name="windowCloseOnTouchOutside" />
         <attr name="windowTranslucentStatus" />
@@ -1775,6 +1773,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 +6111,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 +6339,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 +6654,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..2d60b86 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -31,7 +31,6 @@
   <java-symbol type="id" name="account_type" />
   <java-symbol type="id" name="action_bar" />
   <java-symbol type="id" name="action_bar_container" />
-  <java-symbol type="id" name="action_bar_overlay_layout" />
   <java-symbol type="id" name="action_bar_title" />
   <java-symbol type="id" name="action_bar_subtitle" />
   <java-symbol type="id" name="action_context_bar" />
@@ -61,6 +60,7 @@
   <java-symbol type="id" name="day" />
   <java-symbol type="id" name="day_names" />
   <java-symbol type="id" name="decrement" />
+  <java-symbol type="id" name="decor_content_parent" />
   <java-symbol type="id" name="default_activity_button" />
   <java-symbol type="id" name="deny_button" />
   <java-symbol type="id" name="description" />
@@ -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 5b35608..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..c351d94e 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 2da8615..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/include/android_runtime/android_hardware_camera2_CameraMetadata.h b/include/android_runtime/android_hardware_camera2_CameraMetadata.h
new file mode 100644
index 0000000..3c76ca5
--- /dev/null
+++ b/include/android_runtime/android_hardware_camera2_CameraMetadata.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 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_HARDWARE_CAMERA2_CAMERAMETADATA_JNI_H
+#define ANDROID_HARDWARE_CAMERA2_CAMERAMETADATA_JNI_H
+
+#include <camera/CameraMetadata.h>
+
+#include "jni.h"
+
+namespace android {
+
+/**
+ * Copies the native metadata for this java object into the given output CameraMetadata object.
+ */
+status_t CameraMetadata_getNativeMetadata(JNIEnv* env, jobject thiz,
+               /*out*/CameraMetadata* metadata);
+
+} /*namespace android*/
+
+#endif /*ANDROID_HARDWARE_CAMERA2_CAMERAMETADATA_JNI_H*/
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/DngCreator.java b/media/java/android/media/DngCreator.java
index b2a38ab..76c6d46 100644
--- a/media/java/android/media/DngCreator.java
+++ b/media/java/android/media/DngCreator.java
@@ -17,9 +17,12 @@
 package android.media;
 
 import android.graphics.Bitmap;
+import android.graphics.ImageFormat;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.impl.CameraMetadataNative;
 import android.location.Location;
+import android.util.Size;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -50,7 +53,7 @@
  * Adobe DNG 1.4.0.0 specification</a>.
  * </p>
  */
-public final class DngCreator {
+public final class DngCreator implements AutoCloseable {
 
     /**
      * Create a new DNG object.
@@ -68,7 +71,12 @@
      *          {@link android.hardware.camera2.CameraCharacteristics}.
      * @param metadata a metadata object to generate tags from.
      */
-    public DngCreator(CameraCharacteristics characteristics, CaptureResult metadata) {/*TODO*/}
+    public DngCreator(CameraCharacteristics characteristics, CaptureResult metadata) {
+        if (characteristics == null || metadata == null) {
+            throw new NullPointerException("Null argument to DngCreator constructor");
+        }
+        nativeInit(characteristics.getNativeCopy(), metadata.getNativeCopy());
+    }
 
     /**
      * Set the orientation value to write.
@@ -92,6 +100,13 @@
      * @return this {@link #DngCreator} object.
      */
     public DngCreator setOrientation(int orientation) {
+
+        if (orientation < ExifInterface.ORIENTATION_UNDEFINED ||
+                orientation > ExifInterface.ORIENTATION_ROTATE_270) {
+            throw new IllegalArgumentException("Orientation " + orientation +
+                    " is not a valid EXIF orientation value");
+        }
+        nativeSetOrientation(orientation);
         return this;
     }
 
@@ -111,6 +126,20 @@
      * @return this {@link #DngCreator} object.
      */
     public DngCreator setThumbnail(Bitmap pixels) {
+        if (pixels == null) {
+            throw new NullPointerException("Null argument to setThumbnail");
+        }
+
+        Bitmap.Config config = pixels.getConfig();
+
+        if (config != Bitmap.Config.ARGB_8888) {
+            pixels = pixels.copy(Bitmap.Config.ARGB_8888, false);
+            if (pixels == null) {
+                throw new IllegalArgumentException("Unsupported Bitmap format " + config);
+            }
+            nativeSetThumbnailBitmap(pixels);
+        }
+
         return this;
     }
 
@@ -130,6 +159,21 @@
      * @return this {@link #DngCreator} object.
      */
     public DngCreator setThumbnail(Image pixels) {
+        if (pixels == null) {
+            throw new NullPointerException("Null argument to setThumbnail");
+        }
+
+        int format = pixels.getFormat();
+        if (format != ImageFormat.YUV_420_888) {
+            throw new IllegalArgumentException("Unsupported image format " + format);
+        }
+
+        Image.Plane[] planes = pixels.getPlanes();
+        nativeSetThumbnailImage(pixels.getWidth(), pixels.getHeight(), planes[0].getBuffer(),
+                planes[0].getRowStride(), planes[0].getPixelStride(), planes[1].getBuffer(),
+                planes[1].getRowStride(), planes[1].getPixelStride(), planes[1].getBuffer(),
+                planes[1].getRowStride(), planes[1].getPixelStride());
+
         return this;
     }
 
@@ -150,7 +194,10 @@
      * @throws java.lang.IllegalArgumentException if the given location object doesn't
      *          contain enough information to set location metadata.
      */
-    public DngCreator setLocation(Location location) { return this; }
+    public DngCreator setLocation(Location location) {
+        /*TODO*/
+        return this;
+    }
 
     /**
      * Set the user description string to write.
@@ -163,6 +210,7 @@
      * @return this {@link #DngCreator} object.
      */
     public DngCreator setDescription(String description) {
+        /*TODO*/
         return this;
     }
 
@@ -172,32 +220,33 @@
      *
      * <p>
      * Raw pixel data must have 16 bits per pixel, and the input must contain at least
-     * {@code offset + 2 * (stride * (height - 1) + width * height)} bytes.  The width and height of
+     * {@code offset + 2 * width * height)} bytes.  The width and height of
      * the input are taken from the width and height set in the {@link DngCreator} metadata tags,
      * and will typically be equal to the width and height of
-     * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
-     * If insufficient metadata is set to write a well-formatted DNG file, and
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
+     * The pixel layout in the input is determined from the reported color filter arrangement (CFA)
+     * set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}.  If insufficient
+     * metadata is available to write a well-formatted DNG file, an
      * {@link java.lang.IllegalStateException} will be thrown.
      * </p>
      *
-     * <p>
-     * When reading from the pixel input, {@code stride} pixels will be skipped
-     * after each row (excluding the last).
-     * </p>
-     *
      * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
+     * @param size the {@link Size} of the image to write, in pixels.
      * @param pixels an {@link java.io.InputStream} of pixel data to write.
-     * @param stride the stride of the raw image in pixels.
      * @param offset the offset of the raw image in bytes.  This indicates how many bytes will
      *               be skipped in the input before any pixel data is read.
      *
      * @throws IOException if an error was encountered in the input or output stream.
      * @throws java.lang.IllegalStateException if not enough metadata information has been
      *          set to write a well-formatted DNG file.
+     * @throws java.lang.IllegalArgumentException if the size passed in does not match the
      */
-    public void writeInputStream(OutputStream dngOutput, InputStream pixels, int stride,
-                                 long offset) throws IOException {
-        /*TODO*/
+    public void writeInputStream(OutputStream dngOutput, Size size, InputStream pixels, long offset)
+            throws IOException {
+        if (dngOutput == null || pixels == null) {
+            throw new NullPointerException("Null argument to writeImage");
+        }
+        nativeWriteInputStream(dngOutput, pixels, offset);
     }
 
     /**
@@ -206,22 +255,18 @@
      *
      * <p>
      * Raw pixel data must have 16 bits per pixel, and the input must contain at least
-     * {@code offset + 2 * (stride * (height - 1) + width * height)} bytes.  The width and height of
+     * {@code offset + 2 * width * height)} bytes.  The width and height of
      * the input are taken from the width and height set in the {@link DngCreator} metadata tags,
      * and will typically be equal to the width and height of
-     * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
-     * If insufficient metadata is set to write a well-formatted DNG file, and
+     * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE}.
+     * The pixel layout in the input is determined from the reported color filter arrangement (CFA)
+     * set in {@link CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}.  If insufficient
+     * metadata is available to write a well-formatted DNG file, an
      * {@link java.lang.IllegalStateException} will be thrown.
      * </p>
      *
-     * <p>
-     * When reading from the pixel input, {@code stride} pixels will be skipped
-     * after each row (excluding the last).
-     * </p>
-     *
      * @param dngOutput an {@link java.io.OutputStream} to write the DNG file to.
      * @param pixels an {@link java.nio.ByteBuffer} of pixel data to write.
-     * @param stride the stride of the raw image in pixels.
      * @param offset the offset of the raw image in bytes.  This indicates how many bytes will
      *               be skipped in the input before any pixel data is read.
      *
@@ -229,8 +274,13 @@
      * @throws java.lang.IllegalStateException if not enough metadata information has been
      *          set to write a well-formatted DNG file.
      */
-    public void writeByteBuffer(OutputStream dngOutput, ByteBuffer pixels, int stride,
-                                long offset) throws IOException {/*TODO*/}
+    public void writeByteBuffer(OutputStream dngOutput, Size size, ByteBuffer pixels, long offset)
+            throws IOException {
+        if (dngOutput == null || pixels == null) {
+            throw new NullPointerException("Null argument to writeImage");
+        }
+        nativeWriteByteBuffer(dngOutput, pixels, offset);
+    }
 
     /**
      * Write the pixel data to a DNG file with the currently configured metadata.
@@ -249,6 +299,70 @@
      * @throws java.lang.IllegalStateException if not enough metadata information has been
      *          set to write a well-formatted DNG file.
      */
-    public void writeImage(OutputStream dngOutput, Image pixels) throws IOException {/*TODO*/}
+    public void writeImage(OutputStream dngOutput, Image pixels) throws IOException {
+        if (dngOutput == null || pixels == null) {
+            throw new NullPointerException("Null argument to writeImage");
+        }
 
+        int format = pixels.getFormat();
+        if (format != ImageFormat.RAW_SENSOR) {
+            throw new IllegalArgumentException("Unsupported image format " + format);
+        }
+
+        Image.Plane[] planes = pixels.getPlanes();
+        nativeWriteImage(dngOutput, pixels.getWidth(), pixels.getHeight(), planes[0].getBuffer(),
+                planes[0].getRowStride(), planes[0].getPixelStride());
+    }
+
+    @Override
+    public void close() {
+        nativeDestroy();
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * This field is used by native code, do not access or modify.
+     */
+    private long mNativeContext;
+
+    private static native void nativeClassInit();
+
+    private synchronized native void nativeInit(CameraMetadataNative nativeCharacteristics,
+                                                CameraMetadataNative nativeResult);
+
+    private synchronized native void nativeDestroy();
+
+    private synchronized native void nativeSetOrientation(int orientation);
+
+    private synchronized native void nativeSetThumbnailBitmap(Bitmap bitmap);
+
+    private synchronized native void nativeSetThumbnailImage(int width, int height,
+                                                             ByteBuffer yBuffer, int yRowStride,
+                                                             int yPixStride, ByteBuffer uBuffer,
+                                                             int uRowStride, int uPixStride,
+                                                             ByteBuffer vBuffer, int vRowStride,
+                                                             int vPixStride);
+
+    private synchronized native void nativeWriteImage(OutputStream out, int width, int height,
+                                                      ByteBuffer rawBuffer, int rowStride,
+                                                      int pixStride) throws IOException;
+
+    private synchronized native void nativeWriteByteBuffer(OutputStream out, ByteBuffer rawBuffer,
+                                                           long offset) throws IOException;
+
+    private synchronized native void nativeWriteInputStream(OutputStream out, InputStream rawStream,
+                                                            long offset) throws IOException;
+
+    static {
+        System.loadLibrary("media_jni");
+        nativeClassInit();
+    }
 }
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/jni/Android.mk b/media/jni/Android.mk
index 90fe695..d658654 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -2,6 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
+    android_media_DngCreator.cpp \
     android_media_ImageReader.cpp \
     android_media_MediaCrypto.cpp \
     android_media_MediaCodec.cpp \
@@ -41,6 +42,7 @@
     libjhead \
     libexif \
     libstagefright_amrnb_common \
+    libimg_utils \
 
 LOCAL_REQUIRED_MODULES := \
     libjhead_jni
@@ -53,6 +55,7 @@
     external/tremor/Tremor \
     frameworks/base/core/jni \
     frameworks/av/media/libmedia \
+    frameworks/av/media/img_utils/include \
     frameworks/av/media/libstagefright \
     frameworks/av/media/libstagefright/codecs/amrnb/enc/src \
     frameworks/av/media/libstagefright/codecs/amrnb/common \
diff --git a/media/jni/android_media_DngCreator.cpp b/media/jni/android_media_DngCreator.cpp
new file mode 100644
index 0000000..860d896
--- /dev/null
+++ b/media/jni/android_media_DngCreator.cpp
@@ -0,0 +1,772 @@
+/*
+ * Copyright 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DngCreator_JNI"
+
+#include <system/camera_metadata.h>
+#include <camera/CameraMetadata.h>
+#include <img_utils/DngUtils.h>
+#include <img_utils/TagDefinitions.h>
+#include <img_utils/TiffIfd.h>
+#include <img_utils/TiffWriter.h>
+#include <img_utils/Output.h>
+
+#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/RefBase.h>
+#include <cutils/properties.h>
+
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/android_hardware_camera2_CameraMetadata.h"
+
+#include <jni.h>
+#include <JNIHelp.h>
+
+using namespace android;
+using namespace img_utils;
+
+#define BAIL_IF_INVALID(expr, jnienv, tagId) \
+    if ((expr) != OK) { \
+        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
+                "Invalid metadata for tag %x", tagId); \
+        return; \
+    }
+
+#define BAIL_IF_EMPTY(entry, jnienv, tagId) \
+    if (entry.count == 0) { \
+        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
+                "Missing metadata fields for tag %x", tagId); \
+        return; \
+    }
+
+#define ANDROID_MEDIA_DNGCREATOR_CTX_JNI_ID     "mNativeContext"
+
+static struct {
+    jfieldID mNativeContext;
+} gDngCreatorClassInfo;
+
+static struct {
+    jmethodID mWriteMethod;
+} gOutputStreamClassInfo;
+
+enum {
+    BITS_PER_SAMPLE = 16,
+    BYTES_PER_SAMPLE = 2,
+    TIFF_IFD_0 = 0
+};
+
+// ----------------------------------------------------------------------------
+
+// This class is not intended to be used across JNI calls.
+class JniOutputStream : public Output, public LightRefBase<JniOutputStream> {
+public:
+    JniOutputStream(JNIEnv* env, jobject outStream);
+
+    virtual ~JniOutputStream();
+
+    status_t open();
+    status_t write(const uint8_t* buf, size_t offset, size_t count);
+    status_t close();
+private:
+    enum {
+        BYTE_ARRAY_LENGTH = 1024
+    };
+    jobject mOutputStream;
+    JNIEnv* mEnv;
+    jbyteArray mByteArray;
+};
+
+JniOutputStream::JniOutputStream(JNIEnv* env, jobject outStream) : mOutputStream(outStream),
+        mEnv(env) {
+    mByteArray = env->NewByteArray(BYTE_ARRAY_LENGTH);
+    if (mByteArray == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", "Could not allocate byte array.");
+    }
+}
+
+JniOutputStream::~JniOutputStream() {
+    mEnv->DeleteLocalRef(mByteArray);
+}
+
+status_t JniOutputStream::open() {
+    // Do nothing
+    return OK;
+}
+
+status_t JniOutputStream::write(const uint8_t* buf, size_t offset, size_t count) {
+    while(count > 0) {
+        size_t len = BYTE_ARRAY_LENGTH;
+        len = (count > len) ? len : count;
+        mEnv->SetByteArrayRegion(mByteArray, 0, len, reinterpret_cast<const jbyte*>(buf + offset));
+
+        if (mEnv->ExceptionCheck()) {
+            return BAD_VALUE;
+        }
+
+        mEnv->CallVoidMethod(mOutputStream, gOutputStreamClassInfo.mWriteMethod, mByteArray,
+                0, len);
+
+        if (mEnv->ExceptionCheck()) {
+            return BAD_VALUE;
+        }
+
+        count -= len;
+        offset += len;
+    }
+    return OK;
+}
+
+status_t JniOutputStream::close() {
+    // Do nothing
+    return OK;
+}
+
+// ----------------------------------------------------------------------------
+
+extern "C" {
+
+static TiffWriter* DngCreator_getCreator(JNIEnv* env, jobject thiz) {
+    ALOGV("%s:", __FUNCTION__);
+    return reinterpret_cast<TiffWriter*>(env->GetLongField(thiz,
+            gDngCreatorClassInfo.mNativeContext));
+}
+
+static void DngCreator_setCreator(JNIEnv* env, jobject thiz, sp<TiffWriter> writer) {
+    ALOGV("%s:", __FUNCTION__);
+    TiffWriter* current = DngCreator_getCreator(env, thiz);
+    if (writer != NULL) {
+        writer->incStrong((void*) DngCreator_setCreator);
+    }
+    if (current) {
+        current->decStrong((void*) DngCreator_setCreator);
+    }
+    env->SetLongField(thiz, gDngCreatorClassInfo.mNativeContext,
+            reinterpret_cast<jlong>(writer.get()));
+}
+
+static void DngCreator_nativeClassInit(JNIEnv* env, jclass clazz) {
+    ALOGV("%s:", __FUNCTION__);
+
+    gDngCreatorClassInfo.mNativeContext = env->GetFieldID(clazz,
+            ANDROID_MEDIA_DNGCREATOR_CTX_JNI_ID, "J");
+    LOG_ALWAYS_FATAL_IF(gDngCreatorClassInfo.mNativeContext == NULL,
+            "can't find android/media/DngCreator.%s", ANDROID_MEDIA_DNGCREATOR_CTX_JNI_ID);
+
+    jclass outputStreamClazz = env->FindClass("java/io/OutputStream");
+    LOG_ALWAYS_FATAL_IF(outputStreamClazz == NULL, "Can't find java/io/OutputStream class");
+    gOutputStreamClassInfo.mWriteMethod = env->GetMethodID(outputStreamClazz, "write", "([BII)V");
+    LOG_ALWAYS_FATAL_IF(gOutputStreamClassInfo.mWriteMethod == NULL, "Can't find write method");
+}
+
+static void DngCreator_init(JNIEnv* env, jobject thiz, jobject characteristicsPtr,
+        jobject resultsPtr) {
+    ALOGV("%s:", __FUNCTION__);
+    CameraMetadata characteristics;
+    CameraMetadata results;
+    if (CameraMetadata_getNativeMetadata(env, characteristicsPtr, &characteristics) != OK) {
+         jniThrowException(env, "java/lang/AssertionError",
+                "No native metadata defined for camera characteristics.");
+         return;
+    }
+    if (CameraMetadata_getNativeMetadata(env, resultsPtr, &results) != OK) {
+        jniThrowException(env, "java/lang/AssertionError",
+                "No native metadata defined for capture results.");
+        return;
+    }
+
+    sp<TiffWriter> writer = new TiffWriter();
+
+    writer->addIfd(TIFF_IFD_0);
+
+    status_t err = OK;
+
+    const uint32_t samplesPerPixel = 1;
+    const uint32_t bitsPerSample = BITS_PER_SAMPLE;
+    const uint32_t bitsPerByte = BITS_PER_SAMPLE / BYTES_PER_SAMPLE;
+    uint32_t imageWidth = 0;
+    uint32_t imageHeight = 0;
+
+    OpcodeListBuilder::CfaLayout opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
+
+    // TODO: Greensplit.
+    // TODO: UniqueCameraModel
+    // TODO: Add remaining non-essential tags
+    {
+        // Set orientation
+        uint16_t orientation = 1; // Normal
+        BAIL_IF_INVALID(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0), env,
+                TAG_ORIENTATION);
+    }
+
+    {
+        // Set subfiletype
+        uint32_t subfileType = 0; // Main image
+        BAIL_IF_INVALID(writer->addEntry(TAG_NEWSUBFILETYPE, 1, &subfileType, TIFF_IFD_0), env,
+                TAG_NEWSUBFILETYPE);
+    }
+
+    {
+        // Set bits per sample
+        uint16_t bits = static_cast<uint16_t>(bitsPerSample);
+        BAIL_IF_INVALID(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0), env,
+                TAG_BITSPERSAMPLE);
+    }
+
+    {
+        // Set compression
+        uint16_t compression = 1; // None
+        BAIL_IF_INVALID(writer->addEntry(TAG_COMPRESSION, 1, &compression, TIFF_IFD_0), env,
+                TAG_COMPRESSION);
+    }
+
+    {
+        // Set dimensions
+        camera_metadata_entry entry =
+                characteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+        BAIL_IF_EMPTY(entry, env, TAG_IMAGEWIDTH);
+        uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
+        uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
+        BAIL_IF_INVALID(writer->addEntry(TAG_IMAGEWIDTH, 1, &width, TIFF_IFD_0), env,
+                TAG_IMAGEWIDTH);
+        BAIL_IF_INVALID(writer->addEntry(TAG_IMAGELENGTH, 1, &height, TIFF_IFD_0), env,
+                TAG_IMAGELENGTH);
+        imageWidth = width;
+        imageHeight = height;
+    }
+
+    {
+        // Set photometric interpretation
+        uint16_t interpretation = 32803;
+        BAIL_IF_INVALID(writer->addEntry(TAG_PHOTOMETRICINTERPRETATION, 1, &interpretation,
+                TIFF_IFD_0), env, TAG_PHOTOMETRICINTERPRETATION);
+    }
+
+    {
+        // Set blacklevel tags
+        camera_metadata_entry entry =
+                characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
+        BAIL_IF_EMPTY(entry, env, TAG_BLACKLEVEL);
+        const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32);
+        BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel, TIFF_IFD_0), env,
+                TAG_BLACKLEVEL);
+
+        uint16_t repeatDim[2] = {2, 2};
+        BAIL_IF_INVALID(writer->addEntry(TAG_BLACKLEVELREPEATDIM, 2, repeatDim, TIFF_IFD_0), env,
+                TAG_BLACKLEVELREPEATDIM);
+    }
+
+    {
+        // Set samples per pixel
+        uint16_t samples = static_cast<uint16_t>(samplesPerPixel);
+        BAIL_IF_INVALID(writer->addEntry(TAG_SAMPLESPERPIXEL, 1, &samples, TIFF_IFD_0),
+                env, TAG_SAMPLESPERPIXEL);
+    }
+
+    {
+        // Set planar configuration
+        uint16_t config = 1; // Chunky
+        BAIL_IF_INVALID(writer->addEntry(TAG_PLANARCONFIGURATION, 1, &config, TIFF_IFD_0),
+                env, TAG_PLANARCONFIGURATION);
+    }
+
+    {
+        // Set CFA pattern dimensions
+        uint16_t repeatDim[2] = {2, 2};
+        BAIL_IF_INVALID(writer->addEntry(TAG_CFAREPEATPATTERNDIM, 2, repeatDim, TIFF_IFD_0),
+                env, TAG_CFAREPEATPATTERNDIM);
+    }
+
+    {
+        // Set CFA pattern
+        camera_metadata_entry entry =
+                        characteristics.find(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT);
+        BAIL_IF_EMPTY(entry, env, TAG_CFAPATTERN);
+        camera_metadata_enum_android_sensor_info_color_filter_arrangement_t cfa =
+                static_cast<camera_metadata_enum_android_sensor_info_color_filter_arrangement_t>(
+                entry.data.u8[0]);
+        switch(cfa) {
+            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB: {
+                uint8_t cfa[4] = {0, 1, 1, 2};
+                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
+                                                env, TAG_CFAPATTERN);
+                opcodeCfaLayout = OpcodeListBuilder::CFA_RGGB;
+                break;
+            }
+            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG: {
+                uint8_t cfa[4] = {1, 0, 2, 1};
+                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
+                                                env, TAG_CFAPATTERN);
+                opcodeCfaLayout = OpcodeListBuilder::CFA_GRBG;
+                break;
+            }
+            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG: {
+                uint8_t cfa[4] = {1, 2, 0, 1};
+                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
+                                                env, TAG_CFAPATTERN);
+                opcodeCfaLayout = OpcodeListBuilder::CFA_GBRG;
+                break;
+            }
+            case ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR: {
+                uint8_t cfa[4] = {2, 1, 1, 0};
+                BAIL_IF_INVALID(writer->addEntry(TAG_CFAPATTERN, 4, cfa, TIFF_IFD_0),
+                                env, TAG_CFAPATTERN);
+                opcodeCfaLayout = OpcodeListBuilder::CFA_BGGR;
+                break;
+            }
+            default: {
+                jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                            "Invalid metadata for tag %d", TAG_CFAPATTERN);
+                return;
+            }
+        }
+    }
+
+    {
+        // Set CFA plane color
+        uint8_t cfaPlaneColor[3] = {0, 1, 2};
+        BAIL_IF_INVALID(writer->addEntry(TAG_CFAPLANECOLOR, 3, cfaPlaneColor, TIFF_IFD_0),
+                env, TAG_CFAPLANECOLOR);
+    }
+
+    {
+        // Set CFA layout
+        uint16_t cfaLayout = 1;
+        BAIL_IF_INVALID(writer->addEntry(TAG_CFALAYOUT, 1, &cfaLayout, TIFF_IFD_0),
+                env, TAG_CFALAYOUT);
+    }
+
+    {
+        // Set DNG version information
+        uint8_t version[4] = {1, 4, 0, 0};
+        BAIL_IF_INVALID(writer->addEntry(TAG_DNGVERSION, 4, version, TIFF_IFD_0),
+                env, TAG_DNGVERSION);
+
+        uint8_t backwardVersion[4] = {1, 1, 0, 0};
+        BAIL_IF_INVALID(writer->addEntry(TAG_DNGBACKWARDVERSION, 4, backwardVersion, TIFF_IFD_0),
+                env, TAG_DNGBACKWARDVERSION);
+    }
+
+    {
+        // Set whitelevel
+        camera_metadata_entry entry =
+                characteristics.find(ANDROID_SENSOR_INFO_WHITE_LEVEL);
+        BAIL_IF_EMPTY(entry, env, TAG_WHITELEVEL);
+        uint32_t whiteLevel = static_cast<uint32_t>(entry.data.i32[0]);
+        BAIL_IF_INVALID(writer->addEntry(TAG_WHITELEVEL, 1, &whiteLevel, TIFF_IFD_0), env,
+                TAG_WHITELEVEL);
+    }
+
+    {
+        // Set default scale
+        uint32_t defaultScale[4] = {1, 1, 1, 1};
+        BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTSCALE, 2, defaultScale, TIFF_IFD_0),
+                env, TAG_DEFAULTSCALE);
+    }
+
+    bool singleIlluminant = false;
+    {
+        // Set calibration illuminants
+        camera_metadata_entry entry1 =
+            characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT1);
+        BAIL_IF_EMPTY(entry1, env, TAG_CALIBRATIONILLUMINANT1);
+        camera_metadata_entry entry2 =
+            characteristics.find(ANDROID_SENSOR_REFERENCE_ILLUMINANT2);
+        if (entry2.count == 0) {
+            singleIlluminant = true;
+        }
+        uint16_t ref1 = entry1.data.u8[0];
+
+        BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT1, 1, &ref1,
+                TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT1);
+
+        if (!singleIlluminant) {
+            uint16_t ref2 = entry2.data.u8[0];
+            BAIL_IF_INVALID(writer->addEntry(TAG_CALIBRATIONILLUMINANT2, 1, &ref2,
+                    TIFF_IFD_0), env, TAG_CALIBRATIONILLUMINANT2);
+        }
+    }
+
+    {
+        // Set color transforms
+        camera_metadata_entry entry1 =
+            characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM1);
+        BAIL_IF_EMPTY(entry1, env, TAG_COLORMATRIX1);
+
+        int32_t colorTransform1[entry1.count * 2];
+
+        size_t ctr = 0;
+        for(size_t i = 0; i < entry1.count; ++i) {
+            colorTransform1[ctr++] = entry1.data.r[i].numerator;
+            colorTransform1[ctr++] = entry1.data.r[i].denominator;
+        }
+
+        BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX1, entry1.count, colorTransform1, TIFF_IFD_0),
+                env, TAG_COLORMATRIX1);
+
+        if (!singleIlluminant) {
+            camera_metadata_entry entry2 = characteristics.find(ANDROID_SENSOR_COLOR_TRANSFORM2);
+            BAIL_IF_EMPTY(entry2, env, TAG_COLORMATRIX2);
+            int32_t colorTransform2[entry2.count * 2];
+
+            ctr = 0;
+            for(size_t i = 0; i < entry2.count; ++i) {
+                colorTransform2[ctr++] = entry2.data.r[i].numerator;
+                colorTransform2[ctr++] = entry2.data.r[i].denominator;
+            }
+
+            BAIL_IF_INVALID(writer->addEntry(TAG_COLORMATRIX2, entry2.count, colorTransform2, TIFF_IFD_0),
+                    env, TAG_COLORMATRIX2);
+        }
+    }
+
+    {
+        // Set calibration transforms
+        camera_metadata_entry entry1 =
+            characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM1);
+        BAIL_IF_EMPTY(entry1, env, TAG_CAMERACALIBRATION1);
+
+        int32_t calibrationTransform1[entry1.count * 2];
+
+        size_t ctr = 0;
+        for(size_t i = 0; i < entry1.count; ++i) {
+            calibrationTransform1[ctr++] = entry1.data.r[i].numerator;
+            calibrationTransform1[ctr++] = entry1.data.r[i].denominator;
+        }
+
+        BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION1, entry1.count, calibrationTransform1,
+                TIFF_IFD_0), env, TAG_CAMERACALIBRATION1);
+
+        if (!singleIlluminant) {
+            camera_metadata_entry entry2 =
+                characteristics.find(ANDROID_SENSOR_CALIBRATION_TRANSFORM2);
+            BAIL_IF_EMPTY(entry2, env, TAG_CAMERACALIBRATION2);
+            int32_t calibrationTransform2[entry2.count * 2];
+
+            ctr = 0;
+            for(size_t i = 0; i < entry2.count; ++i) {
+                calibrationTransform2[ctr++] = entry2.data.r[i].numerator;
+                calibrationTransform2[ctr++] = entry2.data.r[i].denominator;
+            }
+
+            BAIL_IF_INVALID(writer->addEntry(TAG_CAMERACALIBRATION2, entry2.count, calibrationTransform1,
+                    TIFF_IFD_0),  env, TAG_CAMERACALIBRATION2);
+        }
+    }
+
+    {
+        // Set forward transforms
+        camera_metadata_entry entry1 =
+            characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX1);
+        BAIL_IF_EMPTY(entry1, env, TAG_FORWARDMATRIX1);
+
+        int32_t forwardTransform1[entry1.count * 2];
+
+        size_t ctr = 0;
+        for(size_t i = 0; i < entry1.count; ++i) {
+            forwardTransform1[ctr++] = entry1.data.r[i].numerator;
+            forwardTransform1[ctr++] = entry1.data.r[i].denominator;
+        }
+
+        BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX1, entry1.count, forwardTransform1,
+                TIFF_IFD_0), env, TAG_FORWARDMATRIX1);
+
+        if (!singleIlluminant) {
+            camera_metadata_entry entry2 =
+                characteristics.find(ANDROID_SENSOR_FORWARD_MATRIX2);
+            BAIL_IF_EMPTY(entry2, env, TAG_FORWARDMATRIX2);
+            int32_t forwardTransform2[entry2.count * 2];
+
+            ctr = 0;
+            for(size_t i = 0; i < entry2.count; ++i) {
+                forwardTransform2[ctr++] = entry2.data.r[i].numerator;
+                forwardTransform2[ctr++] = entry2.data.r[i].denominator;
+            }
+
+            BAIL_IF_INVALID(writer->addEntry(TAG_FORWARDMATRIX2, entry2.count, forwardTransform2,
+                    TIFF_IFD_0),  env, TAG_FORWARDMATRIX2);
+        }
+    }
+
+    {
+        // Set camera neutral
+        camera_metadata_entry entry =
+            results.find(ANDROID_SENSOR_NEUTRAL_COLOR_POINT);
+        BAIL_IF_EMPTY(entry, env, TAG_ASSHOTNEUTRAL);
+        uint32_t cameraNeutral[entry.count * 2];
+
+        size_t ctr = 0;
+        for(size_t i = 0; i < entry.count; ++i) {
+            cameraNeutral[ctr++] =
+                    static_cast<uint32_t>(entry.data.r[i].numerator);
+            cameraNeutral[ctr++] =
+                    static_cast<uint32_t>(entry.data.r[i].denominator);
+        }
+
+        BAIL_IF_INVALID(writer->addEntry(TAG_ASSHOTNEUTRAL, entry.count, cameraNeutral,
+                TIFF_IFD_0), env, TAG_ASSHOTNEUTRAL);
+    }
+
+    {
+        // Setup data strips
+        // TODO: Switch to tiled implementation.
+        uint32_t offset = 0;
+        BAIL_IF_INVALID(writer->addEntry(TAG_STRIPOFFSETS, 1, &offset, TIFF_IFD_0), env,
+                TAG_STRIPOFFSETS);
+
+        BAIL_IF_INVALID(writer->addEntry(TAG_ROWSPERSTRIP, 1, &imageHeight, TIFF_IFD_0), env,
+                TAG_ROWSPERSTRIP);
+
+        uint32_t byteCount = imageWidth * imageHeight * bitsPerSample * samplesPerPixel /
+                bitsPerByte;
+        BAIL_IF_INVALID(writer->addEntry(TAG_STRIPBYTECOUNTS, 1, &byteCount, TIFF_IFD_0), env,
+                TAG_STRIPBYTECOUNTS);
+    }
+
+    {
+        // Setup default crop + crop origin tags
+        uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
+        uint32_t dimensionLimit = 128; // Smallest image dimension crop margin from.
+        if (imageWidth >= dimensionLimit && imageHeight >= dimensionLimit) {
+            uint32_t defaultCropOrigin[] = {margin, margin};
+            uint32_t defaultCropSize[] = {imageWidth - margin, imageHeight - margin};
+            BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin,
+                    TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN);
+            BAIL_IF_INVALID(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize,
+                    TIFF_IFD_0), env, TAG_DEFAULTCROPSIZE);
+        }
+    }
+
+    {
+        // Setup unique camera model tag
+        char model[PROPERTY_VALUE_MAX];
+        property_get("ro.product.model", model, "");
+
+        char manufacturer[PROPERTY_VALUE_MAX];
+        property_get("ro.product.manufacturer", manufacturer, "");
+
+        char brand[PROPERTY_VALUE_MAX];
+        property_get("ro.product.brand", brand, "");
+
+        String8 cameraModel(model);
+        cameraModel += "-";
+        cameraModel += manufacturer;
+        cameraModel += "-";
+        cameraModel += brand;
+
+        BAIL_IF_INVALID(writer->addEntry(TAG_UNIQUECAMERAMODEL, cameraModel.size() + 1,
+                reinterpret_cast<const uint8_t*>(cameraModel.string()), TIFF_IFD_0), env,
+                TAG_UNIQUECAMERAMODEL);
+    }
+
+    {
+        // Setup opcode List 2
+        camera_metadata_entry entry1 =
+                characteristics.find(ANDROID_LENS_INFO_SHADING_MAP_SIZE);
+        BAIL_IF_EMPTY(entry1, env, TAG_OPCODELIST2);
+        uint32_t lsmWidth = static_cast<uint32_t>(entry1.data.i32[0]);
+        uint32_t lsmHeight = static_cast<uint32_t>(entry1.data.i32[1]);
+
+        camera_metadata_entry entry2 =
+                results.find(ANDROID_STATISTICS_LENS_SHADING_MAP);
+        BAIL_IF_EMPTY(entry2, env, TAG_OPCODELIST2);
+        if (entry2.count == lsmWidth * lsmHeight * 4) {
+
+            OpcodeListBuilder builder;
+            status_t err = builder.addGainMapsForMetadata(lsmWidth,
+                                                          lsmHeight,
+                                                          0,
+                                                          0,
+                                                          imageHeight,
+                                                          imageWidth,
+                                                          opcodeCfaLayout,
+                                                          entry2.data.f);
+            if (err == OK) {
+                size_t listSize = builder.getSize();
+                uint8_t opcodeListBuf[listSize];
+                err = builder.buildOpList(opcodeListBuf);
+                if (err == OK) {
+                    BAIL_IF_INVALID(writer->addEntry(TAG_OPCODELIST2, listSize, opcodeListBuf,
+                            TIFF_IFD_0), env, TAG_OPCODELIST2);
+                } else {
+                    ALOGE("%s: Could not build Lens shading map opcode.", __FUNCTION__);
+                    jniThrowRuntimeException(env, "failed to construct lens shading map opcode.");
+                }
+            } else {
+                ALOGE("%s: Could not add Lens shading map.", __FUNCTION__);
+                jniThrowRuntimeException(env, "failed to add lens shading map.");
+            }
+        } else {
+            ALOGW("%s: Lens shading map not present in results, skipping...", __FUNCTION__);
+        }
+    }
+
+    DngCreator_setCreator(env, thiz, writer);
+}
+
+static void DngCreator_destroy(JNIEnv* env, jobject thiz) {
+    ALOGV("%s:", __FUNCTION__);
+    DngCreator_setCreator(env, thiz, NULL);
+}
+
+static void DngCreator_nativeSetOrientation(JNIEnv* env, jobject thiz) {
+    ALOGV("%s:", __FUNCTION__);
+    jniThrowRuntimeException(env, "nativeSetOrientation is not implemented");
+}
+
+static void DngCreator_nativeSetThumbnailBitmap(JNIEnv* env, jobject thiz, jobject bitmap) {
+    ALOGV("%s:", __FUNCTION__);
+    jniThrowRuntimeException(env, "nativeSetThumbnailBitmap is not implemented");
+}
+
+static void DngCreator_nativeSetThumbnailImage(JNIEnv* env, jobject thiz, jint width, jint height,
+        jobject yBuffer, jint yRowStride, jint yPixStride, jobject uBuffer, jint uRowStride,
+        jint uPixStride, jobject vBuffer, jint vRowStride, jint vPixStride) {
+    ALOGV("%s:", __FUNCTION__);
+    jniThrowRuntimeException(env, "nativeSetThumbnailImage is not implemented");
+}
+
+static void DngCreator_nativeWriteImage(JNIEnv* env, jobject thiz, jobject outStream, jint width,
+        jint height, jobject inBuffer, jint rowStride, jint pixStride) {
+    ALOGV("%s:", __FUNCTION__);
+
+    sp<JniOutputStream> out = new JniOutputStream(env, outStream);
+    if(env->ExceptionCheck()) {
+        ALOGE("%s: Could not allocate buffers for output stream", __FUNCTION__);
+        return;
+    }
+
+    uint8_t* pixelBytes = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(inBuffer));
+    if (pixelBytes == NULL) {
+        ALOGE("%s: Could not get native byte buffer", __FUNCTION__);
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid bytebuffer");
+        return;
+    }
+
+    TiffWriter* writer = DngCreator_getCreator(env, thiz);
+    if (writer == NULL) {
+        ALOGE("%s: Failed to initialize DngCreator", __FUNCTION__);
+        jniThrowException(env, "java/lang/AssertionError",
+                "Write called with uninitialized DngCreator");
+        return;
+    }
+    // TODO: handle lens shading map, etc. conversions for other raw buffer sizes.
+    uint32_t metadataWidth = *(writer->getEntry(TAG_IMAGEWIDTH, TIFF_IFD_0)->getData<uint32_t>());
+    uint32_t metadataHeight = *(writer->getEntry(TAG_IMAGELENGTH, TIFF_IFD_0)->getData<uint32_t>());
+    if (metadataWidth != width) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException", \
+                        "Metadata width %d doesn't match image width %d", metadataWidth, width);
+        return;
+    }
+
+    if (metadataHeight != height) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException", \
+                        "Metadata height %d doesn't match image height %d", metadataHeight, height);
+        return;
+    }
+
+    uint32_t stripOffset = writer->getTotalSize();
+
+    BAIL_IF_INVALID(writer->addEntry(TAG_STRIPOFFSETS, 1, &stripOffset, TIFF_IFD_0), env,
+                    TAG_STRIPOFFSETS);
+
+    if (writer->write(out.get()) != OK) {
+        if (!env->ExceptionCheck()) {
+            jniThrowException(env, "java/io/IOException", "Failed to write metadata");
+        }
+        return;
+    }
+
+    size_t fullSize = rowStride * height;
+    jlong capacity = env->GetDirectBufferCapacity(inBuffer);
+    if (capacity < 0 || fullSize > capacity) {
+        jniThrowExceptionFmt(env, "java/lang/IllegalStateException",
+                "Invalid size %d for Image, size given in metadata is %d at current stride",
+                capacity, fullSize);
+        return;
+    }
+
+    if (pixStride == BYTES_PER_SAMPLE && rowStride == width * BYTES_PER_SAMPLE) {
+        if (out->write(pixelBytes, 0, fullSize) != OK || env->ExceptionCheck()) {
+            if (!env->ExceptionCheck()) {
+                jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
+            }
+            return;
+        }
+    } else if (pixStride == BYTES_PER_SAMPLE) {
+        for (size_t i = 0; i < height; ++i) {
+            if (out->write(pixelBytes, i * rowStride, pixStride * width) != OK ||
+                        env->ExceptionCheck()) {
+                if (!env->ExceptionCheck()) {
+                    jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
+                }
+                return;
+            }
+        }
+    } else {
+        for (size_t i = 0; i < height; ++i) {
+            for (size_t j = 0; j < width; ++j) {
+                if (out->write(pixelBytes, i * rowStride + j * pixStride,
+                        BYTES_PER_SAMPLE) != OK || !env->ExceptionCheck()) {
+                    if (env->ExceptionCheck()) {
+                        jniThrowException(env, "java/io/IOException", "Failed to write pixel data");
+                    }
+                    return;
+                }
+            }
+        }
+    }
+
+}
+
+static void DngCreator_nativeWriteByteBuffer(JNIEnv* env, jobject thiz, jobject outStream,
+        jobject rawBuffer, jlong offset) {
+    ALOGV("%s:", __FUNCTION__);
+    jniThrowRuntimeException(env, "nativeWriteByteBuffer is not implemented.");
+}
+
+static void DngCreator_nativeWriteInputStream(JNIEnv* env, jobject thiz, jobject outStream,
+        jobject inStream, jlong offset) {
+    ALOGV("%s:", __FUNCTION__);
+    jniThrowRuntimeException(env, "nativeWriteInputStream is not implemented.");
+}
+
+} /*extern "C" */
+
+static JNINativeMethod gDngCreatorMethods[] = {
+    {"nativeClassInit",        "()V", (void*) DngCreator_nativeClassInit},
+    {"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;"
+            "Landroid/hardware/camera2/impl/CameraMetadataNative;)V", (void*) DngCreator_init},
+    {"nativeDestroy",           "()V",      (void*) DngCreator_destroy},
+    {"nativeSetOrientation",    "(I)V",     (void*) DngCreator_nativeSetOrientation},
+    {"nativeSetThumbnailBitmap","(Landroid/graphics/Bitmap;)V",
+            (void*) DngCreator_nativeSetThumbnailBitmap},
+    {"nativeSetThumbnailImage",
+            "(IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)V",
+            (void*) DngCreator_nativeSetThumbnailImage},
+    {"nativeWriteImage",        "(Ljava/io/OutputStream;IILjava/nio/ByteBuffer;II)V",
+            (void*) DngCreator_nativeWriteImage},
+    {"nativeWriteByteBuffer",    "(Ljava/io/OutputStream;Ljava/nio/ByteBuffer;J)V",
+            (void*) DngCreator_nativeWriteByteBuffer},
+    {"nativeWriteInputStream",    "(Ljava/io/OutputStream;Ljava/io/InputStream;J)V",
+            (void*) DngCreator_nativeWriteInputStream},
+};
+
+int register_android_media_DngCreator(JNIEnv *env) {
+    return AndroidRuntime::registerNativeMethods(env,
+                   "android/media/DngCreator", gDngCreatorMethods, NELEM(gDngCreatorMethods));
+}
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 6f42057..9d03cc3 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -884,6 +884,7 @@
                 "android/media/MediaPlayer", gMethods, NELEM(gMethods));
 }
 
+extern int register_android_media_DngCreator(JNIEnv *env);
 extern int register_android_media_ImageReader(JNIEnv *env);
 extern int register_android_media_Crypto(JNIEnv *env);
 extern int register_android_media_Drm(JNIEnv *env);
@@ -913,6 +914,11 @@
     }
     assert(env != NULL);
 
+    if (register_android_media_DngCreator(env) < 0) {
+        ALOGE("ERROR: ImageReader native registration failed");
+        goto bail;
+    }
+
     if (register_android_media_ImageReader(env) < 0) {
         ALOGE("ERROR: ImageReader native registration failed");
         goto bail;
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/InputDevices/res/raw/keyboard_layout_latvian_qwerty.kcm b/packages/InputDevices/res/raw/keyboard_layout_latvian_qwerty.kcm
new file mode 100644
index 0000000..d4bc0c0
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_latvian_qwerty.kcm
@@ -0,0 +1,362 @@
+# 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.
+
+#
+# Latvian (QWERTY-US-intl based) keyboard layout.
+#
+
+type OVERLAY
+
+map key 86 BACKSLASH
+map key 43 POUND
+
+### ROW 1
+
+key GRAVE {
+    label:                              '\u0300'
+    base:                               '\u0300'
+    shift:                              '\u0303'
+    ralt:                               '-'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '!'
+    ralt:                               '\u00a0'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '@'
+    ralt:                               '\u00ab'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '#'
+    ralt:                               '\u00bb'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              '$'
+    ralt:                               '\u20ac'
+    ralt+shift:                         '\u00a7'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              '%'
+    ralt+shift:                         '\u00b0'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              '\u0302'
+    ralt:                               '\u2019'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '&'
+    ralt+shift:                         '\u00b1'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              '*'
+    ralt+shift:                         '\u00d7'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              '('
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              ')'
+}
+
+key MINUS {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+    ralt:                               '\u2013'
+    ralt+shift:                         '\u2014'
+}
+
+key EQUALS {
+    label:                              '='
+    base:                               '='
+    shift:                              '+'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+    ralt:                               '\u0113'
+    shift+ralt, ralt+capslock:          '\u0112'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+    ralt:                               '\u0157'
+    shift+ralt, ralt+capslock:          '\u0156'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+    ralt:                               '\u016b'
+    shift+ralt, ralt+capslock:          '\u016a'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+    ralt:                               '\u012b'
+    shift+ralt, ralt+capslock:          '\u012a'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift, capslock:                    'O'
+    ralt:                               '\u00f5'
+    shift+ralt, ralt+capslock:          '\u00d5'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '['
+    base:                               '['
+    shift:                              '{'
+}
+
+key RIGHT_BRACKET {
+    label:                              ']'
+    base:                               ']'
+    shift:                              '}'
+}
+
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+    ralt:                               '\u0101'
+    shift+ralt, ralt+capslock:          '\u0100'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+    ralt:                               '\u0161'
+    shift+ralt, ralt+capslock:          '\u0160'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+    ralt:                               '\u0123'
+    shift+ralt, ralt+capslock:          '\u0122'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+    ralt:                               '\u0137'
+    shift+ralt, ralt+capslock:          '\u0136'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+    ralt:                               '\u013c'
+    shift+ralt, ralt+capslock:          '\u013b'
+}
+
+key SEMICOLON {
+    label:                              ';'
+    base:                               ';'
+    shift:                              ':'
+}
+
+key APOSTROPHE {
+    label:                              '\''
+    base:                               '\''
+    shift:                              '"'
+    ralt:                               '\u0301'
+    shift+ralt:                         '\u0308'
+}
+
+key POUND {
+    label:                              '\u00b0'
+    base:                               '\u00b0'
+    shift:                              '|'
+}
+
+### ROW 4
+
+key BACKSLASH {
+    label:                              '\\'
+    base:                               '\\'
+    shift:                              '|'
+    ralt:                               '\u00ac'
+    shift+ralt:                         '\u00a6'
+}
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+    ralt:                               '\u017e'
+    shift+ralt, ralt+capslock:          '\u017d'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+    ralt:                               '\u010d'
+    shift+ralt, ralt+capslock:          '\u010c'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+    ralt:                               '\u0146'
+    shift+ralt, ralt+capslock:          '\u0145'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              '<'
+}
+
+key PERIOD {
+    label:                              '.'
+    base:                               '.'
+    shift:                              '>'
+}
+
+key SLASH {
+    label:                              '/'
+    base:                               '/'
+    shift:                              '?'
+    ralt:                               '\u00bf'
+}
diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml
index 6239336..968961a 100644
--- a/packages/InputDevices/res/values/strings.xml
+++ b/packages/InputDevices/res/values/strings.xml
@@ -113,4 +113,7 @@
 
     <!-- Spanish (Latin) keyboard layout label. [CHAR LIMIT=35] -->
     <string name="keyboard_layout_spanish_latin">Spanish (Latin)</string>
+
+    <!-- Latvian keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_latvian">Latvian</string>
 </resources>
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index dc1db0b..6f7253c 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -143,4 +143,8 @@
     <keyboard-layout android:name="keyboard_layout_spanish_latin"
             android:label="@string/keyboard_layout_spanish_latin"
             android:keyboardLayout="@raw/keyboard_layout_spanish_latin" />
+
+    <keyboard-layout android:name="keyboard_layout_latvian"
+            android:label="@string/keyboard_layout_latvian"
+            android:keyboardLayout="@raw/keyboard_layout_latvian_qwerty" />
 </keyboard-layouts>
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index 0d943ed..f79819f 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -28,8 +28,6 @@
     androidprv:layout_maxWidth="@dimen/keyguard_security_width"
     androidprv:layout_maxHeight="@dimen/keyguard_security_height"
     android:gravity="center_horizontal|top"
-    android:layout_marginTop="48dp"
-    android:layout_marginBottom="32dp"
     android:contentDescription="@string/keyguard_accessibility_status">
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/packages/Keyguard/res/values-sw600dp-land/dimens.xml b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
index 5507e5f..5615ff7 100644
--- a/packages/Keyguard/res/values-sw600dp-land/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp-land/dimens.xml
@@ -23,4 +23,8 @@
 
     <!-- Size of margin on the right of keyguard's status view -->
     <dimen name="kg_status_line_font_right_margin">16dp</dimen>
+
+    <!-- Overload default clock widget parameters -->
+    <dimen name="widget_big_font_size">88dp</dimen>
+    <dimen name="bottom_text_spacing_digital">-24dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml
index 25e86e1..a5e93dc 100644
--- a/packages/Keyguard/res/values-sw600dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw600dp/dimens.xml
@@ -63,8 +63,9 @@
     <dimen name="keyguard_muliuser_selector_margin">12dp</dimen>
 
     <!-- Overload default clock widget parameters -->
-    <dimen name="widget_label_font_size">16dp</dimen>
-    <dimen name="widget_big_font_size">141dp</dimen>
+    <dimen name="widget_big_font_size">96dp</dimen>
+    <dimen name="widget_label_font_size">16sp</dimen>
+    <dimen name="bottom_text_spacing_digital">-24dp</dimen>
 
     <!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text.
          Should be 0 on devices with plenty of room (e.g. tablets) -->
diff --git a/packages/Keyguard/res/values-sw720dp/dimens.xml b/packages/Keyguard/res/values-sw720dp/dimens.xml
index 30b979c..c487072 100644
--- a/packages/Keyguard/res/values-sw720dp/dimens.xml
+++ b/packages/Keyguard/res/values-sw720dp/dimens.xml
@@ -61,7 +61,4 @@
     <!-- Height of the sliding KeyguardSecurityContainer (includes 2x keyguard_security_view_margin) -->
     <dimen name="keyguard_security_height">420dp</dimen>
 
-    <!-- Default clock parameters -->
-    <dimen name="widget_label_font_size">19dp</dimen>
-
 </resources>
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index c05f834..6224aed 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -155,10 +155,10 @@
     <dimen name="eca_overlap">-10dip</dimen>
 
     <!-- Default clock parameters -->
-    <dimen name="bottom_text_spacing_digital">-8dp</dimen>
+    <dimen name="bottom_text_spacing_digital">-18dp</dimen>
     <dimen name="label_font_size">14dp</dimen>
-    <dimen name="widget_label_font_size">14dp</dimen>
-    <dimen name="widget_big_font_size">60dp</dimen>
+    <dimen name="widget_label_font_size">14sp</dimen>
+    <dimen name="widget_big_font_size">68dp</dimen>
     <dimen name="big_font_size">120dp</dimen>
 
 </resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 8425c48..94edc07 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -42,6 +42,8 @@
     private boolean mIsBouncing;
     private SecurityCallback mSecurityCallback;
 
+    private final KeyguardUpdateMonitor mUpdateMonitor;
+
     // Used to notify the container when something interesting happens.
     public interface SecurityCallback {
         public boolean dismiss(boolean authenticated);
@@ -62,6 +64,7 @@
         super(context, attrs, defStyle);
         mSecurityModel = new KeyguardSecurityModel(context);
         mLockPatternUtils = new LockPatternUtils(context);
+        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
     }
 
     public void setSecurityCallback(SecurityCallback callback) {
@@ -303,7 +306,9 @@
     boolean showNextSecurityScreenOrFinish(boolean authenticated) {
         if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
         boolean finish = false;
-        if (SecurityMode.None == mCurrentSecuritySelection) {
+        if (mUpdateMonitor.getUserHasTrust(mLockPatternUtils.getCurrentUser())) {
+            finish = true;
+        } else if (SecurityMode.None == mCurrentSecuritySelection) {
             SecurityMode securityMode = mSecurityModel.getSecurityMode();
             // Allow an alternate, such as biometric unlock
             securityMode = mSecurityModel.getAlternateFor(securityMode);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
index 2d492db..5ef41c9 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -83,8 +83,6 @@
         } else if (simState == IccCardConstants.State.PUK_REQUIRED
                 && mLockPatternUtils.isPukUnlockScreenEnable()) {
             mode = SecurityMode.SimPuk;
-        } else if (updateMonitor.getUserHasTrust(mLockPatternUtils.getCurrentUser())) {
-            mode = SecurityMode.None;
         } else {
             final int security = mLockPatternUtils.getKeyguardStoredPasswordQuality();
             switch (security) {
diff --git a/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml b/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
index 1511911..7904927 100644
--- a/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
+++ b/packages/Keyguard/test/SampleTrustAgent/AndroidManifest.xml
@@ -22,6 +22,7 @@
       <service
           android:name=".SampleTrustAgent"
           android:label="@string/app_name"
+          android:permission="android.permission.BIND_TRUST_AGENT"
           android:exported="true">
         <intent-filter>
           <action android:name="android.service.trust.TrustAgentService" />
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_airplane_off.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_off.png
deleted file mode 100644
index 6f48fe8..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_on.png
deleted file mode 100644
index 5f2e95a..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_not_connected.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_not_connected.png
deleted file mode 100644
index e417a19..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_not_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_off.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_off.png
deleted file mode 100644
index f325220..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_on.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_on.png
deleted file mode 100644
index ee88a1b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_bluetooth_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_0.png
deleted file mode 100644
index 48606a8..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_1.png
deleted file mode 100644
index d006f13..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_2.png
deleted file mode 100644
index 867947b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_cast_connecting_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_color_space_alpha.png
deleted file mode 100644
index fe6dc52..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_color_space_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-hdpi/ic_qs_inversion_alpha.png
deleted file mode 100644
index aea75c1..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_qs_inversion_alpha.png
+++ /dev/null
Binary files differ
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-hdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 58f67d0..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index b794c9a..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_full.png
deleted file mode 100644
index fa23e85..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_full.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_limited.png
deleted file mode 100644
index aa8635c..0000000
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_zen_limited.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_off.png
deleted file mode 100644
index c36809b..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_on.png
deleted file mode 100644
index 6158c01..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index f3e9da2..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index a90aef9..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_off.png
deleted file mode 100644
index 084799a..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_on.png
deleted file mode 100644
index c37ba79..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index b05bf78..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index 2f782cf..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_off.png
deleted file mode 100644
index 714f07e..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_on.png
deleted file mode 100644
index d59f0e9..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 8299301..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index e171d53..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_off.png
deleted file mode 100644
index 6fc556d..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_on.png
deleted file mode 100644
index a2342fc..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 1c847da..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index d0ab910..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_off.png
deleted file mode 100644
index 95df4d45..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_on.png
deleted file mode 100644
index 251fc30..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_not_connected.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_not_connected.png
deleted file mode 100644
index b01b27f..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_not_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_off.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_off.png
deleted file mode 100644
index 541e801..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_on.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_on.png
deleted file mode 100644
index 0acf3a4..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_bluetooth_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_0.png
deleted file mode 100644
index 25fc759..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_1.png
deleted file mode 100644
index 9dfc3c6..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_2.png
deleted file mode 100644
index 82f4113..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_cast_connecting_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_color_space_alpha.png
deleted file mode 100644
index 18b6029..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_color_space_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-mdpi/ic_qs_inversion_alpha.png
deleted file mode 100644
index b6ea14e..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_qs_inversion_alpha.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-mdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 1e05a91..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index f4afa52..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_full.png
deleted file mode 100644
index b0185a5..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_full.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_limited.png
deleted file mode 100644
index 949ab10..0000000
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_zen_limited.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_off.png
deleted file mode 100644
index 4411097..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_on.png
deleted file mode 100644
index 79e4ff6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_not_connected.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_not_connected.png
deleted file mode 100644
index ce965c2..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_not_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_off.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_off.png
deleted file mode 100644
index c798fd6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_on.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_on.png
deleted file mode 100644
index ac5b09d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_bluetooth_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_0.png
deleted file mode 100644
index 945c606..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_1.png
deleted file mode 100644
index 0a3f73e..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_2.png
deleted file mode 100644
index 398cbef..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_cast_connecting_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_color_space_alpha.png
deleted file mode 100644
index 95cf67f..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_color_space_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-xhdpi/ic_qs_inversion_alpha.png
deleted file mode 100644
index efd8b9e..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_qs_inversion_alpha.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-xhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index 662d062..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index 18be9c0..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_full.png
deleted file mode 100644
index 7f7cb63..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_full.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_limited.png
deleted file mode 100644
index abdeb3b..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_zen_limited.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_off.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_off.png
deleted file mode 100644
index 65b0204..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_on.png
deleted file mode 100644
index dd16165..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_airplane_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_not_connected.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_not_connected.png
deleted file mode 100644
index c5b7333..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_not_connected.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_off.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_off.png
deleted file mode 100644
index 1045e07..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_off.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_on.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_on.png
deleted file mode 100644
index 7c20110..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_bluetooth_on.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_0.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_0.png
deleted file mode 100644
index 4621d18..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_0.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_1.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_1.png
deleted file mode 100644
index a1ab61b..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_1.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_2.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_2.png
deleted file mode 100644
index ea42a7f..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_cast_connecting_2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_color_space_alpha.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_color_space_alpha.png
deleted file mode 100644
index 7f441c8..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_color_space_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_inversion_alpha.png b/packages/SystemUI/res/drawable-xxhdpi/ic_qs_inversion_alpha.png
deleted file mode 100644
index ce9bae2..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_qs_inversion_alpha.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-xxhdpi/stat_sys_ringer_silent.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png
deleted file mode 100644
index aabf0aa..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_silent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png
deleted file mode 100644
index 654c2a5..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_ringer_vibrate.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_full.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_full.png
deleted file mode 100644
index afe85b4..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_full.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_limited.png b/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_limited.png
deleted file mode 100644
index 5e5053f..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/stat_sys_zen_limited.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane.xml b/packages/SystemUI/res/drawable/ic_qs_airplane_off.xml
similarity index 85%
copy from packages/SystemUI/res/drawable/ic_qs_airplane.xml
copy to packages/SystemUI/res/drawable/ic_qs_airplane_off.xml
index ffe571f..9f0ec67 100644
--- a/packages/SystemUI/res/drawable/ic_qs_airplane.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_airplane_off.xml
@@ -23,9 +23,13 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#00000000"
+        android:stroke="#CCCCCC"
+        android:strokeWidth="1.0"
         android:pathData="M10.2,9.0"/>
     <path
-        android:fill="#FF000000"
+        android:fill="#00000000"
+        android:stroke="#CCCCCC"
+        android:strokeWidth="1.0"
         android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane.xml b/packages/SystemUI/res/drawable/ic_qs_airplane_on.xml
similarity index 94%
rename from packages/SystemUI/res/drawable/ic_qs_airplane.xml
rename to packages/SystemUI/res/drawable/ic_qs_airplane_on.xml
index ffe571f..95c20bb 100644
--- a/packages/SystemUI/res/drawable/ic_qs_airplane.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_airplane_on.xml
@@ -23,9 +23,9 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#FFFFFFFF"
         android:pathData="M10.2,9.0"/>
     <path
-        android:fill="#FF000000"
+        android:fill="#FFFFFFFF"
         android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
similarity index 96%
rename from packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
rename to packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
index 22d0dcf..61a7777 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#FFFFFFFF"
         android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml
similarity index 91%
copy from packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
copy to packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml
index 22d0dcf..7ac1cb9 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_off.xml
@@ -23,6 +23,8 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#00000000"
+        android:stroke="#CCCCCC"
+        android:strokeWidth="1.0"
         android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
similarity index 96%
copy from packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
copy to packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
index 22d0dcf..61a7777 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#FFFFFFFF"
         android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bugreport.xml b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
index 2dfe183..2958848 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bugreport.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#FFFFFFFF"
         android:pathData="M20.0,8.0l-2.8,0.0c-0.5,-0.8 -1.1,-1.5 -1.8,-2.0L17.0,4.4L15.6,3.0l-2.2,2.2C13.0,5.1 12.5,5.0 12.0,5.0s-1.0,0.1 -1.4,0.2L8.4,3.0L7.0,4.4L8.6,6.0C7.9,6.5 7.3,7.2 6.8,8.0L4.0,8.0l0.0,2.0l2.1,0.0C6.0,10.3 6.0,10.7 6.0,11.0l0.0,1.0L4.0,12.0l0.0,2.0l2.0,0.0l0.0,1.0c0.0,0.3 0.0,0.7 0.1,1.0L4.0,16.0l0.0,2.0l2.8,0.0c1.0,1.8 3.0,3.0 5.2,3.0s4.2,-1.2 5.2,-3.0L20.0,18.0l0.0,-2.0l-2.1,0.0c0.1,-0.3 0.1,-0.7 0.1,-1.0l0.0,-1.0l2.0,0.0l0.0,-2.0l-2.0,0.0l0.0,-1.0c0.0,-0.3 0.0,-0.7 -0.1,-1.0L20.0,10.0L20.0,8.0zM14.0,16.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,16.0zM14.0,12.0l-4.0,0.0l0.0,-2.0l4.0,0.0L14.0,12.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_connecting.xml b/packages/SystemUI/res/drawable/ic_qs_cast_connecting.xml
deleted file mode 100644
index 70db2a9..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_cast_connecting.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<animation-list
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:oneshot="false">
-    <item android:drawable="@drawable/ic_qs_cast_connecting_0" android:duration="500" />
-    <item android:drawable="@drawable/ic_qs_cast_connecting_1" android:duration="500" />
-    <item android:drawable="@drawable/ic_qs_cast_connecting_2" android:duration="500" />
-    <item android:drawable="@drawable/ic_qs_cast_connecting_1" android:duration="500" />
-</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast.xml b/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
similarity index 92%
copy from packages/SystemUI/res/drawable/ic_qs_cast.xml
copy to packages/SystemUI/res/drawable/ic_qs_cast_off.xml
index 6f2840b..130c639 100644
--- a/packages/SystemUI/res/drawable/ic_qs_cast.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
@@ -23,6 +23,8 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#00000000"
+        android:stroke="#CCCCCC"
+        android:strokeWidth="1.0"
         android:pathData="M21.0,3.0L3.0,3.0C1.9,3.0 1.0,3.9 1.0,5.0l0.0,3.0l2.0,0.0L3.0,5.0l18.0,0.0l0.0,14.0l-7.0,0.0l0.0,2.0l7.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L23.0,5.0C23.0,3.9 22.1,3.0 21.0,3.0zM1.0,18.0l0.0,3.0l3.0,0.0C4.0,19.3 2.7,18.0 1.0,18.0zM1.0,14.0l0.0,2.0c2.8,0.0 5.0,2.2 5.0,5.0l2.0,0.0C8.0,17.1 4.9,14.0 1.0,14.0zM1.0,10.0l0.0,2.0c5.0,0.0 9.0,4.0 9.0,9.0l2.0,0.0C12.0,14.9 7.1,10.0 1.0,10.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast.xml b/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
similarity index 97%
rename from packages/SystemUI/res/drawable/ic_qs_cast.xml
rename to packages/SystemUI/res/drawable/ic_qs_cast_on.xml
index 6f2840b..6c82b1c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_cast.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#FFFFFFFF"
         android:pathData="M21.0,3.0L3.0,3.0C1.9,3.0 1.0,3.9 1.0,5.0l0.0,3.0l2.0,0.0L3.0,5.0l18.0,0.0l0.0,14.0l-7.0,0.0l0.0,2.0l7.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L23.0,5.0C23.0,3.9 22.1,3.0 21.0,3.0zM1.0,18.0l0.0,3.0l3.0,0.0C4.0,19.3 2.7,18.0 1.0,18.0zM1.0,14.0l0.0,2.0c2.8,0.0 5.0,2.2 5.0,5.0l2.0,0.0C8.0,17.1 4.9,14.0 1.0,14.0zM1.0,10.0l0.0,2.0c5.0,0.0 9.0,4.0 9.0,9.0l2.0,0.0C12.0,14.9 7.1,10.0 1.0,10.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_close.xml b/packages/SystemUI/res/drawable/ic_qs_close.xml
index c2c72c8..dd43e6c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_close.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_close.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#FFFFFFFF"
         android:pathData="M19.0,6.4l-1.3999996,-1.4000001 -5.6000004,5.6000004 -5.6,-5.6000004 -1.4000001,1.4000001 5.6000004,5.6 -5.6000004,5.6000004 1.4000001,1.3999996 5.6,-5.6000004 5.6000004,5.6000004 1.3999996,-1.3999996 -5.6000004,-5.6000004z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml b/packages/SystemUI/res/drawable/ic_qs_color_inversion.xml
similarity index 97%
rename from packages/SystemUI/res/drawable/ic_qs_invert_colors.xml
rename to packages/SystemUI/res/drawable/ic_qs_color_inversion.xml
index 7c92052..dc30a53 100644
--- a/packages/SystemUI/res/drawable/ic_qs_invert_colors.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_color_inversion.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#FFFFFFFF"
         android:pathData="M18.939,7.244c-5.887,-5.885 -6.214,-6.214 -6.222,-6.222l-0.707,-0.737L5.088,7.207c-2.914,2.915 -3.74,6.629 -2.266,10.19c1.541,3.719 5.312,6.316 9.174,6.317l0.0,0.0c3.861,-0.001 7.636,-2.603 9.179,-6.328C22.646,13.834 21.832,10.138 18.939,7.244zM4.67,16.632c-1.149,-2.776 -0.481,-5.696 1.832,-8.011l5.494,-5.492c0.0,0.002 0.002,0.003 0.003,0.004l0.0,18.582c-0.001,0.0 -0.002,0.0 -0.003,0.0C8.922,21.714 5.91,19.624 4.67,16.632z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_color_space_off.xml b/packages/SystemUI/res/drawable/ic_qs_color_space_off.xml
deleted file mode 100644
index cf34ba6..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_color_space_off.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_qs_color_space_alpha"
-    android:tint="@color/ic_qs_off" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_color_space_on.xml b/packages/SystemUI/res/drawable/ic_qs_color_space_on.xml
deleted file mode 100644
index 1806688..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_color_space_on.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_qs_color_space_alpha"
-    android:tint="@color/ic_qs_on" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_hotspot.xml b/packages/SystemUI/res/drawable/ic_qs_hotspot_off.xml
similarity index 93%
copy from packages/SystemUI/res/drawable/ic_qs_hotspot.xml
copy to packages/SystemUI/res/drawable/ic_qs_hotspot_off.xml
index 965e3c1..7a62212 100644
--- a/packages/SystemUI/res/drawable/ic_qs_hotspot.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_hotspot_off.xml
@@ -23,6 +23,8 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#00000000"
+        android:stroke="#CCCCCC"
+        android:strokeWidth="1.0"
         android:pathData="M12.0,11.0c-1.1,0.0 -2.0,0.9 -2.0,2.0c0.0,1.1 0.9,2.0 2.0,2.0c1.1,0.0 2.0,-0.9 2.0,-2.0C14.0,11.9 13.1,11.0 12.0,11.0zM18.0,13.0c0.0,-3.3 -2.7,-6.0 -6.0,-6.0c-3.3,0.0 -6.0,2.7 -6.0,6.0c0.0,2.2 1.2,4.1 3.0,5.2l1.0,-1.7c-1.2,-0.7 -2.0,-2.0 -2.0,-3.4c0.0,-2.2 1.8,-4.0 4.0,-4.0s4.0,1.8 4.0,4.0c0.0,1.5 -0.8,2.8 -2.0,3.4l1.0,1.7C16.8,17.1 18.0,15.2 18.0,13.0zM12.0,3.0C6.5,3.0 2.0,7.5 2.0,13.0c0.0,3.7 2.0,6.9 5.0,8.6l1.0,-1.7c-2.4,-1.4 -4.0,-4.0 -4.0,-6.9c0.0,-4.4 3.6,-8.0 8.0,-8.0s8.0,3.6 8.0,8.0c0.0,3.0 -1.6,5.5 -4.0,6.9l1.0,1.7c3.0,-1.7 5.0,-5.0 5.0,-8.6C22.0,7.5 17.5,3.0 12.0,3.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_hotspot.xml b/packages/SystemUI/res/drawable/ic_qs_hotspot_on.xml
similarity index 97%
rename from packages/SystemUI/res/drawable/ic_qs_hotspot.xml
rename to packages/SystemUI/res/drawable/ic_qs_hotspot_on.xml
index 965e3c1..3ccdd81 100644
--- a/packages/SystemUI/res/drawable/ic_qs_hotspot.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_hotspot_on.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#FFFFFFFF"
         android:pathData="M12.0,11.0c-1.1,0.0 -2.0,0.9 -2.0,2.0c0.0,1.1 0.9,2.0 2.0,2.0c1.1,0.0 2.0,-0.9 2.0,-2.0C14.0,11.9 13.1,11.0 12.0,11.0zM18.0,13.0c0.0,-3.3 -2.7,-6.0 -6.0,-6.0c-3.3,0.0 -6.0,2.7 -6.0,6.0c0.0,2.2 1.2,4.1 3.0,5.2l1.0,-1.7c-1.2,-0.7 -2.0,-2.0 -2.0,-3.4c0.0,-2.2 1.8,-4.0 4.0,-4.0s4.0,1.8 4.0,4.0c0.0,1.5 -0.8,2.8 -2.0,3.4l1.0,1.7C16.8,17.1 18.0,15.2 18.0,13.0zM12.0,3.0C6.5,3.0 2.0,7.5 2.0,13.0c0.0,3.7 2.0,6.9 5.0,8.6l1.0,-1.7c-2.4,-1.4 -4.0,-4.0 -4.0,-6.9c0.0,-4.4 3.6,-8.0 8.0,-8.0s8.0,3.6 8.0,8.0c0.0,3.0 -1.6,5.5 -4.0,6.9l1.0,1.7c3.0,-1.7 5.0,-5.0 5.0,-8.6C22.0,7.5 17.5,3.0 12.0,3.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml
deleted file mode 100644
index 9018a90..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_inversion_off.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_qs_inversion_alpha"
-    android:tint="@color/ic_qs_off" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml b/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
deleted file mode 100644
index 9110201..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_inversion_on.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_qs_inversion_alpha"
-    android:tint="@color/ic_qs_on" />
diff --git a/packages/SystemUI/res/drawable/ic_qs_location.xml b/packages/SystemUI/res/drawable/ic_qs_location.xml
deleted file mode 100644
index e6e98a0..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_location.xml
+++ /dev/null
@@ -1,28 +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.
--->
-<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="#FF000000"
-        android:pathData="M12.0,2.0C8.1,2.0 5.0,5.1 5.0,9.0c0.0,5.2 7.0,13.0 7.0,13.0s7.0,-7.8 7.0,-13.0C19.0,5.1 15.9,2.0 12.0,2.0zM12.0,11.5c-1.4,0.0 -2.5,-1.1 -2.5,-2.5s1.1,-2.5 2.5,-2.5c1.4,0.0 2.5,1.1 2.5,2.5S13.4,11.5 12.0,11.5z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_location_01.xml
similarity index 75%
copy from packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
copy to packages/SystemUI/res/drawable/ic_qs_location_01.xml
index 22d0dcf..ff37d9a 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_01.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
+        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_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_location_02.xml
similarity index 74%
copy from packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
copy to packages/SystemUI/res/drawable/ic_qs_location_02.xml
index 22d0dcf..bb4465f 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_02.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
+        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_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_location_03.xml
similarity index 73%
copy from packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
copy to packages/SystemUI/res/drawable/ic_qs_location_03.xml
index 22d0dcf..956a8c3 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_03.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
+        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_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_location_04.xml
similarity index 74%
copy from packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
copy to packages/SystemUI/res/drawable/ic_qs_location_04.xml
index 22d0dcf..0c0fb3b 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_04.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
+        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_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_location_05.xml
similarity index 72%
copy from packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
copy to packages/SystemUI/res/drawable/ic_qs_location_05.xml
index 22d0dcf..1a21e2f 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_05.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
+        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_qs_location_06.xml b/packages/SystemUI/res/drawable/ic_qs_location_06.xml
new file mode 100644
index 0000000..25c9ae5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_location_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_qs_airplane.xml b/packages/SystemUI/res/drawable/ic_qs_location_07.xml
similarity index 70%
copy from packages/SystemUI/res/drawable/ic_qs_airplane.xml
copy to packages/SystemUI/res/drawable/ic_qs_location_07.xml
index ffe571f..a69c3a2 100644
--- a/packages/SystemUI/res/drawable/ic_qs_airplane.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_07.xml
@@ -23,9 +23,8 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M10.2,9.0"/>
-    <path
-        android:fill="#FF000000"
-        android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
+        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_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_location_08.xml
similarity index 73%
copy from packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
copy to packages/SystemUI/res/drawable/ic_qs_location_08.xml
index 22d0dcf..c89c047 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_08.xml
@@ -23,6 +23,8 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
+        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_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_location_09.xml
similarity index 71%
copy from packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
copy to packages/SystemUI/res/drawable/ic_qs_location_09.xml
index 22d0dcf..96bb6ce 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_09.xml
@@ -23,6 +23,8 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
+        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_qs_airplane.xml b/packages/SystemUI/res/drawable/ic_qs_location_10.xml
similarity index 70%
copy from packages/SystemUI/res/drawable/ic_qs_airplane.xml
copy to packages/SystemUI/res/drawable/ic_qs_location_10.xml
index ffe571f..aced4bd 100644
--- a/packages/SystemUI/res/drawable/ic_qs_airplane.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_10.xml
@@ -23,9 +23,8 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M10.2,9.0"/>
-    <path
-        android:fill="#FF000000"
-        android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
+        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_qs_bluetooth.xml b/packages/SystemUI/res/drawable/ic_qs_location_11.xml
similarity index 73%
copy from packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
copy to packages/SystemUI/res/drawable/ic_qs_location_11.xml
index 22d0dcf..578308e 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_location_11.xml
@@ -23,6 +23,8 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M17.7,7.7L12.0,2.0l-1.0,0.0l0.0,7.6L6.4,5.0L5.0,6.4l5.6,5.6L5.0,17.6L6.4,19.0l4.6,-4.6L11.0,22.0l1.0,0.0l5.7,-5.7L13.4,12.0L17.7,7.7zM13.0,5.8l1.9,1.9L13.0,9.6L13.0,5.8zM14.9,16.3L13.0,18.2l0.0,-3.8L14.9,16.3z"/>
+        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_qs_location_off.xml b/packages/SystemUI/res/drawable/ic_qs_location_off.xml
new file mode 100644
index 0000000..d28d347
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_location_off.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_qs_location_01" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_02" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_03" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_04" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_05" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_06" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_07" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_08" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_09" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_10" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_11" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_qs_location_on.xml b/packages/SystemUI/res/drawable/ic_qs_location_on.xml
new file mode 100644
index 0000000..72512ac
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_location_on.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_qs_location_11" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_10" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_09" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_08" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_07" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_06" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_05" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_04" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_03" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_02" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_location_01" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_qs_minus.xml b/packages/SystemUI/res/drawable/ic_qs_minus.xml
index 8323e89..376cc28 100644
--- a/packages/SystemUI/res/drawable/ic_qs_minus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_minus.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#FFFFFFFF"
         android:pathData="M7.0,11.0l0.0,2.0l10.0,0.0l0.0,-2.0L7.0,11.0zM12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,20.0c-4.4,0.0 -8.0,-3.6 -8.0,-8.0s3.6,-8.0 8.0,-8.0c4.4,0.0 8.0,3.6 8.0,8.0S16.4,20.0 12.0,20.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_plus.xml b/packages/SystemUI/res/drawable/ic_qs_plus.xml
index 84cd72a..a315f7f 100644
--- a/packages/SystemUI/res/drawable/ic_qs_plus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_plus.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#FFFFFFFF"
         android:pathData="M13.0,7.0l-2.0,0.0l0.0,4.0L7.0,11.0l0.0,2.0l4.0,0.0l0.0,4.0l2.0,0.0l0.0,-4.0l4.0,0.0l0.0,-2.0l-4.0,0.0L13.0,7.0zM12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM12.0,20.0c-4.4,0.0 -8.0,-3.6 -8.0,-8.0s3.6,-8.0 8.0,-8.0c4.4,0.0 8.0,3.6 8.0,8.0S16.4,20.0 12.0,20.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
index fa6f20c..3a20c58 100644
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_audible.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M3.0,9.0c0.0,0.0 0.0,6.0 0.0,6.0l4.0,0.0l5.0,5.0L12.0,4.0L7.0,9.0L3.0,9.0zM16.5,12.0c0.0,-1.8 -1.0,-3.3 -2.5,-4.0L14.0,16.0C15.5,15.3 16.5,13.8 16.5,12.0zM14.0,3.2l0.0,2.1c2.9,0.9 5.0,3.5 5.0,6.7s-2.1,5.8 -5.0,6.7l0.0,2.1c4.0,-0.9 7.0,-4.5 7.0,-8.8S18.0,4.1 14.0,3.2z"/>
+        android:fill="#FFFFFFFF"
+        android:pathData="M6.6,3.6L5.2,2.2C2.8,4.0 1.2,6.8 1.0,10.0l2.0,0.0C3.2,7.3 4.5,5.0 6.6,3.6zM20.0,10.0l2.0,0.0c-0.2,-3.2 -1.7,-6.0 -4.1,-7.8l-1.4,1.4C18.5,5.0 19.8,7.3 20.0,10.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0l-2.0,-2.0L18.0,10.5zM11.5,22.0c0.1,0.0 0.3,0.0 0.4,0.0c0.7,-0.1 1.2,-0.6 1.4,-1.2c0.1,-0.2 0.2,-0.5 0.2,-0.8l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
index 0665196..dd6be76 100644
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_silent.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M16.5,12.0c0.0,-1.8 -1.0,-3.3 -2.5,-4.0l0.0,2.2l2.5,2.5C16.5,12.4 16.5,12.2 16.5,12.0zM19.0,12.0c0.0,0.9 -0.2,1.8 -0.5,2.6l1.5,1.5c0.7,-1.2 1.0,-2.7 1.0,-4.2c0.0,-4.3 -3.0,-7.9 -7.0,-8.8l0.0,2.1C16.9,6.2 19.0,8.8 19.0,12.0zM4.3,3.0L3.0,4.3L7.7,9.0L3.0,9.0c0.0,0.0 0.0,6.0 0.0,6.0l4.0,0.0l5.0,5.0l0.0,-6.7l4.3,4.3c-0.7,0.5 -1.4,0.9 -2.3,1.2l0.0,2.1c1.4,-0.3 2.6,-0.9 3.7,-1.8l2.0,2.0l1.3,-1.3l-9.0,-9.0L4.3,3.0zM12.0,4.0L9.9,6.1L12.0,8.2L12.0,4.0z"/>
+        android:fill="#FFFFFFFF"
+        android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7C9.5,4.3 9.0,4.5 8.6,4.7l9.4,9.4L18.0,10.5zM17.7,19.0l2.0,2.0l1.3,-1.3L4.3,3.0L3.0,4.3l2.9,2.9C5.3,8.2 5.0,9.3 5.0,10.5L5.0,16.0l-2.0,2.0l0.0,1.0L17.7,19.0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
index 299a2ef..96d20e8 100644
--- a/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_ringer_vibrate.xml
@@ -23,6 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
+        android:fill="#FFFFFFFF"
         android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_01.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_01.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_01.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_01.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_02.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_02.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_02.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_02.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_03.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_03.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_03.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_03.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_04.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_04.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_04.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_04.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_05.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_05.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_05.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_05.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_06.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_06.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_06.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_06.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_07.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_07.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_07.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_07.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_08.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_08.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_08.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_08.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_09.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_09.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_09.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_09.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_10.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_10.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_10.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_10.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_11.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_11.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_11.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_11.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_12.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_12.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_12.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_12.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_13.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_13.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_13.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_13.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_14.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_14.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_14.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_14.xml
diff --git a/packages/SystemUI/res/drawable/ic_rotate_24_15.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_15.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_rotate_24_15.xml
rename to packages/SystemUI/res/drawable/ic_qs_rotation_15.xml
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_locked.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_locked.xml
new file mode 100644
index 0000000..75e20f0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_rotation_locked.xml
@@ -0,0 +1,35 @@
+<?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_qs_rotation_01" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_02" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_03" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_04" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_05" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_06" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_07" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_08" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_09" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_10" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_11" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_12" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_13" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_14" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_15" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml b/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml
new file mode 100644
index 0000000..a1cedb9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_rotation_unlocked.xml
@@ -0,0 +1,35 @@
+<?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_qs_rotation_15" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_14" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_13" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_12" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_11" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_10" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_09" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_08" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_07" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_06" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_05" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_04" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_03" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_02" android:duration="16" />
+    <item android:drawable="@drawable/ic_qs_rotation_01" android:duration="16" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_qs_zen.xml b/packages/SystemUI/res/drawable/ic_qs_zen_off.xml
similarity index 66%
copy from packages/SystemUI/res/drawable/ic_qs_zen.xml
copy to packages/SystemUI/res/drawable/ic_qs_zen_off.xml
index 059c068..73886ec 100644
--- a/packages/SystemUI/res/drawable/ic_qs_zen.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_zen_off.xml
@@ -23,6 +23,8 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0zM14.0,9.8l-2.8,3.4L14.0,13.200001L14.0,15.0L9.0,15.0l0.0,-1.8l2.8,-3.4L9.0,9.799999L9.0,8.0l5.0,0.0L14.0,9.8z"/>
+        android:fill="#00000000"
+        android:stroke="#CCCCCC"
+        android:strokeWidth="1.0"
+        android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM4.0,12.0c0.0,-4.4 3.6,-8.0 8.0,-8.0c1.8,0.0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4.0,13.8 4.0,12.0zM12.0,20.0c-1.8,0.0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20.0,10.2 20.0,12.0C20.0,16.4 16.4,20.0 12.0,20.0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane.xml b/packages/SystemUI/res/drawable/ic_qs_zen_on.xml
similarity index 70%
copy from packages/SystemUI/res/drawable/ic_qs_airplane.xml
copy to packages/SystemUI/res/drawable/ic_qs_zen_on.xml
index ffe571f..8dff318 100644
--- a/packages/SystemUI/res/drawable/ic_qs_airplane.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_zen_on.xml
@@ -23,9 +23,6 @@
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M10.2,9.0"/>
-    <path
-        android:fill="#FF000000"
-        android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
+        android:fill="#FFFFFFFF"
+        android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM4.0,12.0c0.0,-4.4 3.6,-8.0 8.0,-8.0c1.8,0.0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4.0,13.8 4.0,12.0zM12.0,20.0c-1.8,0.0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20.0,10.2 20.0,12.0C20.0,16.4 16.4,20.0 12.0,20.0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_locked_anim.xml b/packages/SystemUI/res/drawable/ic_rotate_locked_anim.xml
deleted file mode 100644
index e14a1ce..0000000
--- a/packages/SystemUI/res/drawable/ic_rotate_locked_anim.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<animation-list
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:oneshot="true">
-    <item android:drawable="@drawable/ic_rotate_24_01" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_02" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_03" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_04" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_05" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_06" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_07" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_08" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_09" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_10" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_11" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_12" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_13" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_14" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_15" android:duration="16" />
-</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_rotate_unlocked_anim.xml b/packages/SystemUI/res/drawable/ic_rotate_unlocked_anim.xml
deleted file mode 100644
index 63b8c5f..0000000
--- a/packages/SystemUI/res/drawable/ic_rotate_unlocked_anim.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<animation-list
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:oneshot="true">
-    <item android:drawable="@drawable/ic_rotate_24_15" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_14" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_13" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_12" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_11" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_10" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_09" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_08" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_07" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_06" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_05" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_04" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_03" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_02" android:duration="16" />
-    <item android:drawable="@drawable/ic_rotate_24_01" android:duration="16" />
-</animation-list>
diff --git a/packages/SystemUI/res/drawable/ic_qs_zen.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
similarity index 66%
rename from packages/SystemUI/res/drawable/ic_qs_zen.xml
rename to packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
index 059c068..5efd8ec 100644
--- a/packages/SystemUI/res/drawable/ic_qs_zen.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_silent.xml
@@ -15,14 +15,14 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
     <size
-        android:width="64dp"
-        android:height="64dp"/>
+        android:width="19dp"
+        android:height="19dp"/>
 
     <viewport
         android:viewportWidth="24.0"
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,16.0l0.0,-5.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7c-2.9,0.7 -5.0,3.2 -5.0,6.3L5.0,16.0l-2.0,2.0l0.0,1.0l17.0,0.0l0.0,-1.0L18.0,16.0zM14.0,9.8l-2.8,3.4L14.0,13.200001L14.0,15.0L9.0,15.0l0.0,-1.8l2.8,-3.4L9.0,9.799999L9.0,8.0l5.0,0.0L14.0,9.8z"/>
+        android:fill="#FFFFFFFF"
+        android:pathData="M11.5,22.0c1.1,0.0 2.0,-0.9 2.0,-2.0l-4.0,0.0C9.5,21.1 10.4,22.0 11.5,22.0zM18.0,10.5c0.0,-3.1 -2.1,-5.6 -5.0,-6.3L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5l0.0,0.7C9.5,4.3 9.0,4.5 8.6,4.7l9.4,9.4L18.0,10.5zM17.7,19.0l2.0,2.0l1.3,-1.3L4.3,3.0L3.0,4.3l2.9,2.9C5.3,8.2 5.0,9.3 5.0,10.5L5.0,16.0l-2.0,2.0l0.0,1.0L17.7,19.0z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
similarity index 62%
copy from packages/SystemUI/res/drawable/ic_qs_airplane.xml
copy to packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
index ffe571f..e1d63c3 100644
--- a/packages/SystemUI/res/drawable/ic_qs_airplane.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
@@ -15,17 +15,14 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
     <size
-        android:width="64dp"
-        android:height="64dp"/>
+        android:width="20dp"
+        android:height="20dp"/>
 
     <viewport
         android:viewportWidth="24.0"
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M10.2,9.0"/>
-    <path
-        android:fill="#FF000000"
-        android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
+        android:fill="#FFFFFFFF"
+        android:pathData="M0.0,15.0l2.0,0.0L2.0,9.0L0.0,9.0L0.0,15.0zM3.0,17.0l2.0,0.0L5.0,7.0L3.0,7.0L3.0,17.0zM22.0,9.0l0.0,6.0l2.0,0.0L24.0,9.0L22.0,9.0zM19.0,17.0l2.0,0.0L21.0,7.0l-2.0,0.0L19.0,17.0zM16.5,3.0l-9.0,0.0C6.7,3.0 6.0,3.7 6.0,4.5l0.0,15.0C6.0,20.3 6.7,21.0 7.5,21.0l9.0,0.0c0.8,0.0 1.5,-0.7 1.5,-1.5l0.0,-15.0C18.0,3.7 17.3,3.0 16.5,3.0zM16.0,19.0L8.0,19.0L8.0,5.0l8.0,0.0L16.0,19.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_airplane.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_zen.xml
similarity index 65%
copy from packages/SystemUI/res/drawable/ic_qs_airplane.xml
copy to packages/SystemUI/res/drawable/stat_sys_ringer_zen.xml
index ffe571f..afab88f 100644
--- a/packages/SystemUI/res/drawable/ic_qs_airplane.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_zen.xml
@@ -15,17 +15,14 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android" >
     <size
-        android:width="64dp"
-        android:height="64dp"/>
+        android:width="19dp"
+        android:height="19dp"/>
 
     <viewport
         android:viewportWidth="24.0"
         android:viewportHeight="24.0"/>
 
     <path
-        android:fill="#FF000000"
-        android:pathData="M10.2,9.0"/>
-    <path
-        android:fill="#FF000000"
-        android:pathData="M21.0,16.0l0.0,-2.0l-8.0,-5.0L13.0,3.5C13.0,2.7 12.3,2.0 11.5,2.0C10.7,2.0 10.0,2.7 10.0,3.5L10.0,9.0l-8.0,5.0l0.0,2.0l8.0,-2.5L10.0,19.0l-2.0,1.5L8.0,22.0l3.5,-1.0l3.5,1.0l0.0,-1.5L13.0,19.0l0.0,-5.5L21.0,16.0z"/>
+        android:fill="#FFFFFFFF"
+        android:pathData="M12.0,2.0C6.5,2.0 2.0,6.5 2.0,12.0s4.5,10.0 10.0,10.0c5.5,0.0 10.0,-4.5 10.0,-10.0S17.5,2.0 12.0,2.0zM4.0,12.0c0.0,-4.4 3.6,-8.0 8.0,-8.0c1.8,0.0 3.5,0.6 4.9,1.7L5.7,16.9C4.6,15.5 4.0,13.8 4.0,12.0zM12.0,20.0c-1.8,0.0 -3.5,-0.6 -4.9,-1.7L18.3,7.1C19.4,8.5 20.0,10.2 20.0,12.0C20.0,16.4 16.4,20.0 12.0,20.0z" />
 </vector>
diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
index 2df6d43..b73874a 100644
--- a/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
+++ b/packages/SystemUI/res/layout/qs_zen_mode_detail.xml
@@ -19,8 +19,9 @@
     android:layout_height="match_parent"
     android:background="@color/system_secondary_color" >
 
-    <com.android.systemui.qs.QSImageView
+    <ImageView
         android:id="@android:id/button1"
+        android:src="@drawable/ic_qs_close"
         android:layout_width="64dp"
         android:layout_height="64dp"
         android:layout_alignParentStart="true"
diff --git a/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml b/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
index a5c8903..7e02bee 100644
--- a/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
+++ b/packages/SystemUI/res/layout/qs_zen_mode_detail_condition.xml
@@ -38,8 +38,9 @@
         android:maxLines="1"
         android:text="@string/accessibility_back" />
 
-    <com.android.systemui.qs.QSImageView
+    <ImageView
         android:id="@android:id/button1"
+        android:src="@drawable/ic_qs_plus"
         android:layout_width="64dp"
         android:layout_height="64dp"
         android:layout_alignParentEnd="true"
@@ -47,8 +48,9 @@
         android:padding="@dimen/quick_settings_panel_padding"
         android:paddingRight="0px" />
 
-    <com.android.systemui.qs.QSImageView
+    <ImageView
         android:id="@android:id/button2"
+        android:src="@drawable/ic_qs_minus"
         android:layout_width="64dp"
         android:layout_height="64dp"
         android:layout_alignParentEnd="true"
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 585658e..eaa2558 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -61,11 +61,6 @@
                 android:src="@drawable/stat_notify_more"
                 android:visibility="gone"
                 />
-            <com.android.systemui.statusbar.StatusBarIconView android:id="@+id/modeIcon"
-                android:layout_width="@dimen/status_bar_icon_size"
-                android:layout_height="match_parent"
-                android:visibility="gone"
-                />
             <com.android.systemui.statusbar.phone.IconMerger android:id="@+id/notificationIcons"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
index 30eedee..8348e9b 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -18,7 +18,7 @@
 <com.android.systemui.statusbar.NotificationOverflowContainer
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="40dp"
+    android:layout_height="@dimen/notification_summary_height"
     android:focusable="true"
     android:clickable="true"
     >
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-sw600dp-land/values-land-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
similarity index 85%
rename from packages/SystemUI/res/values-sw600dp-land/values-land-sw600dp/dimens.xml
rename to packages/SystemUI/res/values-sw600dp-land/dimens.xml
index e440de1..b510fef 100644
--- a/packages/SystemUI/res/values-sw600dp-land/values-land-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -18,4 +18,7 @@
 <resources>
     <!-- Recent Applications parameters -->
     <dimen name="status_bar_recents_app_label_width">190dip</dimen>
+
+    <fraction name="keyguard_clock_y_fraction_max">37%</fraction>
+    <fraction name="keyguard_clock_y_fraction_min">14%</fraction>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 7372181..22815f3 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -48,4 +48,15 @@
 
     <!-- Width of the zen mode interstitial dialog. -->
     <dimen name="zen_mode_dialog_width">384dp</dimen>
+
+    <!-- The fraction of the screen height where the clock on the Keyguard has its center. The
+         max value is used when no notifications are displaying, and the min value is when the
+         highest possible number of notifications are showing. -->
+    <fraction name="keyguard_clock_y_fraction_max">34%</fraction>
+    <fraction name="keyguard_clock_y_fraction_min">25%</fraction>
+
+    <!-- The margin between the clock and the notifications on Keyguard. See
+         keyguard_clock_height_fraction_* for the difference between min and max.-->
+    <dimen name="keyguard_clock_notifications_margin_min">32dp</dimen>
+    <dimen name="keyguard_clock_notifications_margin_max">32dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
new file mode 100644
index 0000000..2532dd6
--- /dev/null
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -0,0 +1,23 @@
+<?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
+  -->
+<resources>
+    <!-- The fraction of the screen height where the clock on the Keyguard has its center. The
+         min value is used when no notifications are displaying, and the max value is when the
+         highest possible number of notifications are showing. -->
+    <fraction name="keyguard_clock_y_fraction_max">35%</fraction>
+    <fraction name="keyguard_clock_y_fraction_min">20%</fraction>
+</resources>
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
index 7cf711a..d8bb8d7d 100644
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -35,5 +35,9 @@
 
     <!-- Transposes the search bar layout in landscape -->
     <bool name="recents_transpose_search_layout_with_orientation">false</bool>
+
+    <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
+         card. -->
+    <integer name="keyguard_max_notification_count">5</integer>
 </resources>
 
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index a1c5b66..7695b12 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -65,5 +65,11 @@
     <!-- Where to place the app icon over the thumbnail -->
     <dimen name="status_bar_recents_app_icon_left_margin">0dp</dimen>
     <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen>
+
+    <!-- The fraction of the screen height where the clock on the Keyguard has its center. The
+     max value is used when no notifications are displaying, and the min value is when the
+     highest possible number of notifications are showing. -->
+    <fraction name="keyguard_clock_y_fraction_max">35%</fraction>
+    <fraction name="keyguard_clock_y_fraction_min">25%</fraction>
 </resources>
 
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 7de1bd0..77b4843 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>
@@ -40,8 +41,6 @@
     <color name="system_secondary_color">#ff384248</color>
     <color name="system_accent_color">#ff7fcac3</color>
     <color name="system_error_color">#fff0592b</color>
-    <color name="quick_settings_tile_icon_enabled">#ffffffff</color>
-    <color name="quick_settings_tile_icon_disabled">#ffcccccc</color>
     <color name="quick_settings_tile_divider">#ff888888</color>
     <color name="quick_settings_tile_text">#FFFFFFFF</color>
     <color name="status_bar_clock_color">#FFFFFFFF</color>
@@ -57,6 +56,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..29955dd 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -82,6 +82,9 @@
     <!-- Height of a medium notification in the status bar -->
     <dimen name="notification_mid_height">128dp</dimen>
 
+    <!-- Height of a the summary ("more card") notification on keyguard. -->
+    <dimen name="notification_summary_height">40dp</dimen>
+
     <!-- size at which Notification icons will be drawn in the status bar -->
     <dimen name="status_bar_icon_drawing_size">18dip</dimen>
 
@@ -260,6 +263,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>
 
@@ -272,7 +284,6 @@
     <dimen name="quick_settings_tmp_scrim_stroke_width">8dp</dimen>
     <dimen name="quick_settings_tmp_scrim_text_size">30dp</dimen>
     <dimen name="quick_settings_panel_padding">16dp</dimen>
-    <dimen name="quick_settings_tile_icon_outline">2dp</dimen>
     <dimen name="quick_settings_tile_text_size">12sp</dimen>
     <dimen name="quick_settings_tile_divider_height">1dp</dimen>
 
@@ -280,4 +291,16 @@
     
     <!-- Minimum distance the user has to drag down to go to the full shade. -->
     <dimen name="keyguard_drag_down_min_distance">100dp</dimen>
+
+    <!-- The fraction of the screen height where the clock on the Keyguard has its center. The
+         max value is used when no notifications are displaying, and the min value is when the
+         highest possible number of notifications are showing. -->
+    <fraction name="keyguard_clock_y_fraction_max">29.5%</fraction>
+    <fraction name="keyguard_clock_y_fraction_min">18%</fraction>
+
+    <!-- The margin between the clock and the notifications on Keyguard. See
+         keyguard_clock_height_fraction_* for the difference between min and max.-->
+    <dimen name="keyguard_clock_notifications_margin_min">22dp</dimen>
+    <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen>
+
 </resources>
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..19888a8 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>
 
@@ -192,4 +193,9 @@
     </style>
 
     <style name="QSBorderless" parent="@android:style/Widget.Quantum.Button.Borderless" />
+
+    <style name="QSBorderless.Tiny">
+        <item name="android:minHeight">12dip</item>
+        <item name="android:minWidth">12dip</item>
+    </style>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java b/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java
deleted file mode 100644
index 05c8ee3..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/FilterCanvas.java
+++ /dev/null
@@ -1,79 +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.systemui.qs;
-
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Rect;
-
-/** Canvas that forwards calls to another canvas.  Can be subclassed to transform drawing calls.
- * Temporary solution to runtime modification of a single drawable shape into two
- * enabled & disabled versions.  See QSImageView. **/
-public class FilterCanvas extends Canvas {
-    private final Canvas mCanvas;
-
-    public FilterCanvas(Canvas c) {
-        mCanvas = c;
-    }
-
-    @Override
-    public void drawPath(Path path, Paint paint) {
-        mCanvas.drawPath(path, paint);
-    }
-
-    @Override
-    public int getSaveCount() {
-        return mCanvas.getSaveCount();
-    }
-
-    @Override
-    public int save() {
-        return mCanvas.save();
-    }
-
-    @Override
-    public void translate(float dx, float dy) {
-        mCanvas.translate(dx, dy);
-    }
-
-    @Override
-    public boolean clipRect(int left, int top, int right, int bottom) {
-        return mCanvas.clipRect(left, top, right, bottom);
-    }
-
-    @Override
-    public boolean clipRect(Rect rect) {
-        return mCanvas.clipRect(rect);
-    }
-
-    @Override
-    public void concat(Matrix matrix) {
-        mCanvas.concat(matrix);
-    }
-
-    @Override
-    public void restoreToCount(int saveCount) {
-        mCanvas.restoreToCount(saveCount);
-    }
-
-    @Override
-    public void drawRect(Rect r, Paint paint) {
-        mCanvas.drawRect(r, paint);
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java b/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java
index 1e15b9f..c169df0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/GlobalSetting.java
@@ -21,10 +21,10 @@
 import android.os.Handler;
 import android.provider.Settings.Global;
 
-import com.android.systemui.statusbar.policy.Disposable;
+import com.android.systemui.statusbar.policy.Listenable;
 
 /** Helper for managing a global setting. **/
-public abstract class GlobalSetting extends ContentObserver implements Disposable {
+public abstract class GlobalSetting extends ContentObserver implements Listenable {
     private final Context mContext;
     private final String mSettingName;
 
@@ -34,8 +34,6 @@
         super(handler);
         mContext = context;
         mSettingName = settingName;
-        mContext.getContentResolver().registerContentObserver(
-                Global.getUriFor(mSettingName), false, this);
     }
 
     public int getValue() {
@@ -47,8 +45,13 @@
     }
 
     @Override
-    public void dispose() {
-        mContext.getContentResolver().unregisterContentObserver(this);
+    public void setListening(boolean listening) {
+        if (listening) {
+            mContext.getContentResolver().registerContentObserver(
+                    Global.getUriFor(mSettingName), false, this);
+        } else {
+            mContext.getContentResolver().unregisterContentObserver(this);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java b/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java
deleted file mode 100644
index ed67560..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSImageView.java
+++ /dev/null
@@ -1,102 +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.systemui.qs;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Paint.Style;
-import android.graphics.Path;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.VectorDrawable;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-
-import com.android.systemui.R;
-
-/** ImageView that performs runtime modification of vector drawables (using FilterCanvas). **/
-public class QSImageView extends ImageView {
-
-    private final int mOutlineWidth;
-    private final int mColorEnabled;
-    private final int mColorDisabled;
-    private FilterCanvas mFilterCanvas;
-    private Canvas mCanvas;
-    private boolean mEnabledVersion = true;
-    private boolean mFilter;
-
-    public QSImageView(Context context) {
-        this(context, null);
-    }
-
-    public QSImageView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        final Resources res = context.getResources();
-        mOutlineWidth = res.getDimensionPixelSize(R.dimen.quick_settings_tile_icon_outline);
-        mColorEnabled = res.getColor(R.color.quick_settings_tile_icon_enabled);
-        mColorDisabled = res.getColor(R.color.quick_settings_tile_icon_disabled);
-    }
-
-    public void setEnabledVersion(boolean enabledVersion) {
-        mEnabledVersion = enabledVersion;
-        invalidate();
-    }
-
-    @Override
-    public void setImageDrawable(Drawable drawable) {
-        mFilter = drawable instanceof VectorDrawable;
-        super.setImageDrawable(drawable);
-    }
-
-    @Override
-    public void setImageResource(int resId) {
-        setImageDrawable(mContext.getDrawable(resId));
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        if (mFilter) {
-            if (canvas != mCanvas) {
-                mCanvas = canvas;
-                mFilterCanvas = new QSFilterCanvas(canvas);
-            }
-            super.draw(mFilterCanvas);
-        } else {
-            super.draw(canvas);
-        }
-    }
-
-    private class QSFilterCanvas extends FilterCanvas {
-        public QSFilterCanvas(Canvas c) {
-            super(c);
-        }
-
-        @Override
-        public void drawPath(Path path, Paint paint) {
-            if (mEnabledVersion) {
-                paint.setColor(mColorEnabled);
-            } else {
-                paint.setStyle(Style.STROKE);
-                paint.setStrokeJoin(Paint.Join.ROUND);
-                paint.setColor(mColorDisabled);
-                paint.setStrokeWidth(mOutlineWidth);
-            }
-            super.drawPath(path, paint);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index afb5483..6176eb6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -80,7 +80,10 @@
             showDetail(false /*show*/, mDetailRecord);
         }
         for (TileRecord r : mRecords) {
-            r.tile.setShown(expanded);
+            r.tile.setListening(expanded);
+            if (expanded) {
+                r.tile.refreshState();
+            }
         }
     }
 
@@ -125,6 +128,7 @@
             }
         };
         r.tileView.init(click, clickSecondary);
+        r.tile.refreshState();
         mRecords.add(r);
 
         addView(r.tileView);
@@ -156,24 +160,29 @@
         mCellHeight = (int)(mCellWidth / TILE_ASPECT);
         mLargeCellWidth = (int)(mCellWidth * LARGE_TILE_FACTOR);
         mLargeCellHeight = (int)(mCellHeight * LARGE_TILE_FACTOR);
-        int r = 0;
-        int c = 0;
+        int r = -1;
+        int c = -1;
         int rows = 0;
+        boolean rowIsDual = false;
         for (TileRecord record : mRecords) {
             if (record.tileView.getVisibility() == GONE) continue;
+            // wrap to next column if we've reached the max # of columns
+            // also don't allow dual + single tiles on the same row
+            if (r == -1 || c == (mColumns - 1) || rowIsDual != record.tile.supportsDualTargets()) {
+                r++;
+                c = 0;
+                rowIsDual = record.tile.supportsDualTargets();
+            } else {
+                c++;
+            }
             record.row = r;
             record.col = c;
             rows = r + 1;
-            c++;
-            if (c == mColumns /*end of normal column*/ || r == 0 && c == 2 /*end of 1st column*/) {
-                c = 0;
-                r++;
-            }
         }
 
         for (TileRecord record : mRecords) {
             if (record.tileView.getVisibility() == GONE) continue;
-            record.tileView.setDual(record.row == 0);
+            record.tileView.setDual(record.tile.supportsDualTargets());
             final int cw = record.row == 0 ? mLargeCellWidth : mCellWidth;
             final int ch = record.row == 0 ? mLargeCellHeight : mCellHeight;
             record.tileView.measure(exactly(cw), exactly(ch));
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 05f308d..835a5c4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.VectorDrawable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -30,7 +29,7 @@
 import com.android.systemui.qs.QSTile.State;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.Disposable;
+import com.android.systemui.statusbar.policy.Listenable;
 import com.android.systemui.statusbar.policy.LocationController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.RotationLockController;
@@ -47,8 +46,10 @@
  * handleUpdateState.  Callbacks affecting state should use refreshState to trigger another
  * state update pass on tile looper.
  */
-public abstract class QSTile<TState extends State> implements Disposable {
-    private final String TAG = "QSTile." + getClass().getSimpleName();
+public abstract class QSTile<TState extends State> implements Listenable {
+    protected final String TAG = "QSTile." + getClass().getSimpleName();
+    protected static final boolean DEBUG = false;
+    public static final int FEEDBACK_START_DELAY = 400;
 
     protected final Host mHost;
     protected final Context mContext;
@@ -69,6 +70,10 @@
         mHandler = new H(host.getLooper());
     }
 
+    public boolean supportsDualTargets() {
+        return false;
+    }
+
     public Host getHost() {
         return mHost;
     }
@@ -111,10 +116,6 @@
         mHandler.obtainMessage(H.USER_SWITCH, newUserId).sendToTarget();
     }
 
-    public void setShown(boolean shown) {
-        mHandler.obtainMessage(H.SHOWN, shown ? 1 : 0, 0).sendToTarget();
-    }
-
     // call only on tile worker looper
 
     private void handleSetCallback(Callback callback) {
@@ -126,10 +127,6 @@
         // optional
     }
 
-    protected void handleShown(boolean shown) {
-        // optional, discouraged
-    }
-
     protected void handleRefreshState(Object arg) {
         handleUpdateState(mTmpState, arg);
         final boolean changed = mTmpState.copyTo(mState);
@@ -161,7 +158,6 @@
         private static final int REFRESH_STATE = 4;
         private static final int SHOW_DETAIL = 5;
         private static final int USER_SWITCH = 6;
-        private static final int SHOWN = 7;
 
         private H(Looper looper) {
             super(looper);
@@ -189,9 +185,6 @@
                 } else if (msg.what == USER_SWITCH) {
                     name = "handleUserSwitch";
                     handleUserSwitch(msg.arg1);
-                } else if (msg.what == SHOWN) {
-                    name = "handleShown";
-                    handleShown(msg.arg1 != 0);
                 }
             } catch (Throwable t) {
                 final String error = "Error in " + name;
@@ -212,7 +205,6 @@
         void collapsePanels();
         Looper getLooper();
         Context getContext();
-        VectorDrawable getVectorDrawable(int resId);
         BluetoothController getBluetoothController();
         LocationController getLocationController();
         RotationLockController getRotationLockController();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 17a95fb..4cfb636 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -25,9 +25,11 @@
 import android.os.Looper;
 import android.os.Message;
 import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.ImageView;
 import android.widget.ImageView.ScaleType;
 import android.widget.TextView;
 
@@ -43,9 +45,9 @@
     protected final Context mContext;
     private final View mIcon;
     private final View mDivider;
-    private final TextView mLabel;
     private final H mHandler = new H();
 
+    private TextView mLabel;
     private boolean mDual;
     private OnClickListener mClickPrimary;
     private OnClickListener mClickSecondary;
@@ -55,14 +57,7 @@
 
         mContext = context;
         final Resources res = context.getResources();
-        mLabel = new TextView(mContext);
-        mLabel.setId(android.R.id.title);
-        mLabel.setTextColor(res.getColor(R.color.quick_settings_tile_text));
-        mLabel.setGravity(Gravity.CENTER);
-        mLabel.setTypeface(CONDENSED);
-        mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
-                res.getDimensionPixelSize(R.dimen.quick_settings_tile_text_size));
-        addView(mLabel);
+        recreateLabel();
         setClipChildren(false);
 
         mIcon = createIcon();
@@ -78,8 +73,33 @@
         setBackground(getSelectableBackground());
     }
 
+    private void recreateLabel() {
+        CharSequence labelText = null;
+        if (mLabel != null) {
+            labelText = mLabel.getText();
+            removeView(mLabel);
+        }
+        final Resources res = mContext.getResources();
+        mLabel = new TextView(mDual ? new ContextThemeWrapper(mContext, R.style.QSBorderless_Tiny)
+                : mContext);
+        mLabel.setId(android.R.id.title);
+        mLabel.setTextColor(res.getColor(R.color.quick_settings_tile_text));
+        mLabel.setGravity(Gravity.CENTER);
+        mLabel.setTypeface(CONDENSED);
+        mLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+                res.getDimensionPixelSize(R.dimen.quick_settings_tile_text_size));
+        if (labelText != null) {
+            mLabel.setText(labelText);
+        }
+        addView(mLabel);
+    }
+
     public void setDual(boolean dual) {
+        final boolean changed = dual != mDual;
         mDual = dual;
+        if (changed) {
+            recreateLabel();
+        }
         if (mDual) {
             setOnClickListener(mClickPrimary);
             mLabel.setClickable(true);
@@ -98,7 +118,7 @@
     }
 
     protected View createIcon() {
-        QSImageView icon = new QSImageView(mContext);
+        final ImageView icon = new ImageView(mContext);
         icon.setId(android.R.id.icon);
         icon.setScaleType(ScaleType.CENTER_INSIDE);
         return icon;
@@ -120,9 +140,10 @@
         final int iconSpec = exactly((int)mLabel.getTextSize() * 2);
         mIcon.measure(iconSpec, iconSpec);
         mLabel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.AT_MOST));
-        mLabel.measure(widthMeasureSpec, exactly(mLabel.getMeasuredHeight() + p * 2));
         if (mDual) {
             mDivider.measure(widthMeasureSpec, exactly(mDivider.getLayoutParams().height));
+        } else {
+            mLabel.measure(widthMeasureSpec, exactly(mLabel.getMeasuredHeight() + p * 2));
         }
         setMeasuredDimension(w, h);
     }
@@ -156,15 +177,12 @@
     }
 
     protected void handleStateChanged(QSTile.State state) {
-        if (mIcon instanceof QSImageView) {
-            QSImageView qsiv = (QSImageView) mIcon;
+        if (mIcon instanceof ImageView) {
+            ImageView iv = (ImageView) mIcon;
             if (state.icon != null) {
-                qsiv.setImageDrawable(state.icon);
+                iv.setImageDrawable(state.icon);
             } else if (state.iconId > 0) {
-                qsiv.setImageResource(state.iconId);
-            }
-            if (state.icon != null && state instanceof QSTile.BooleanState) {
-                qsiv.setEnabledVersion(((QSTile.BooleanState)state).value);
+                iv.setImageResource(state.iconId);
             }
         }
         mLabel.setText(state.label);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
index 4debaa9..3ed3d30 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SecureSetting.java
@@ -21,10 +21,10 @@
 import android.os.Handler;
 import android.provider.Settings.Secure;
 
-import com.android.systemui.statusbar.policy.Disposable;
+import com.android.systemui.statusbar.policy.Listenable;
 
 /** Helper for managing a secure setting. **/
-public abstract class SecureSetting extends ContentObserver implements Disposable {
+public abstract class SecureSetting extends ContentObserver implements Listenable {
     private final Context mContext;
     private final String mSettingName;
 
@@ -38,8 +38,7 @@
     }
 
     public void rebindForCurrentUser() {
-        mContext.getContentResolver().registerContentObserver(
-                Secure.getUriFor(mSettingName), false, this);
+        setListening(true);
     }
 
     public int getValue() {
@@ -51,8 +50,13 @@
     }
 
     @Override
-    public void dispose() {
-        mContext.getContentResolver().unregisterContentObserver(this);
+    public void setListening(boolean listening) {
+        if (listening) {
+            mContext.getContentResolver().registerContentObserver(
+                    Secure.getUriFor(mSettingName), false, this);
+        } else {
+            mContext.getContentResolver().unregisterContentObserver(this);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 5fe8422..c0f9bf2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -39,11 +39,6 @@
                 handleRefreshState(value);
             }
         };
-
-        final IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
-        mContext.registerReceiver(mReceiver, filter);
-        refreshState();
     }
 
     @Override
@@ -70,7 +65,6 @@
         state.value = airplaneMode;
         state.visible = true;
         state.label = mContext.getString(R.string.quick_settings_airplane_mode_label);
-        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_airplane);
         if (airplaneMode) {
             state.iconId =  R.drawable.ic_qs_airplane_on;
             state.contentDescription =  mContext.getString(
@@ -84,9 +78,15 @@
         }
     }
 
-    public void dispose() {
-        mSetting.dispose();
-        mContext.unregisterReceiver(mReceiver);
+    public void setListening(boolean listening) {
+        if (listening) {
+            final IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+            mContext.registerReceiver(mReceiver, filter);
+        } else {
+            mContext.unregisterReceiver(mReceiver);
+        }
+        mSetting.setListening(listening);
     }
 
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 60a6047..7335ab4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -33,7 +33,11 @@
     public BluetoothTile(Host host) {
         super(host);
         mController = host.getBluetoothController();
-        mController.addStateChangedCallback(mCallback);
+    }
+
+    @Override
+    public boolean supportsDualTargets() {
+        return true;
     }
 
     @Override
@@ -42,8 +46,12 @@
     }
 
     @Override
-    public void dispose() {
-        mController.removeStateChangedCallback(mCallback);
+    public void setListening(boolean listening) {
+        if (listening) {
+            mController.addStateChangedCallback(mCallback);
+        } else {
+            mController.removeStateChangedCallback(mCallback);
+        }
     }
 
     @Override
@@ -64,14 +72,13 @@
         final boolean connected = mController.isBluetoothConnected();
         state.visible = supported;
         state.value = enabled;
-        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_bluetooth);
         final String stateContentDescription;
         if (enabled) {
             if (connected) {
-                state.iconId = R.drawable.ic_qs_bluetooth_on;
+                state.iconId = R.drawable.ic_qs_bluetooth_connected;
                 stateContentDescription = mContext.getString(R.string.accessibility_desc_connected);
             } else {
-                state.iconId = R.drawable.ic_qs_bluetooth_not_connected;
+                state.iconId = R.drawable.ic_qs_bluetooth_on;
                 stateContentDescription = mContext.getString(R.string.accessibility_desc_on);
             }
             state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
index 0e9b9a7..bfd416d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BugreportTile.java
@@ -51,21 +51,25 @@
     }
 
     @Override
-    public void dispose() {
-        mSetting.dispose();
+    public void setListening(boolean listening) {
+        mSetting.setListening(listening);
     }
 
     @Override
     protected void handleClick() {
-        mHost.collapsePanels();
-        mUiHandler.post(mShowDialog);
+        mHandler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                mHost.collapsePanels();
+                mUiHandler.post(mShowDialog);
+            }
+        }, FEEDBACK_START_DELAY);
     }
 
     @Override
     protected void handleUpdateState(State state, Object pushArg) {
         state.visible = mSetting.getValue() != 0;
-        state.iconId = com.android.internal.R.drawable.stat_sys_adb;
-        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_bugreport);
+        state.iconId = R.drawable.ic_qs_bugreport;
         state.label = mContext.getString(com.android.internal.R.string.bugreport_title);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index a3eaa2c..907c77e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -35,14 +35,9 @@
 
     private final CastController mController;
 
-    private boolean mShown;
-
     public CastTile(Host host) {
         super(host);
         mController = host.getCastController();
-        if (mController != null) {
-            mController.addCallback(mCallback);
-        }
     }
 
     @Override
@@ -51,9 +46,14 @@
     }
 
     @Override
-    public void dispose() {
+    public void setListening(boolean listening) {
         if (mController == null) return;
-        mController.removeCallback(mCallback);
+        if (listening) {
+            mController.addCallback(mCallback);
+        } else {
+            mController.removeCallback(mCallback);
+        }
+        mController.setDiscovering(listening);
     }
 
     @Override
@@ -64,17 +64,13 @@
     }
 
     @Override
-    protected void handleShown(boolean shown) {
-        if (mShown == shown) return;
-        if (mController == null) return;
-        mShown = shown;
-        mController.setDiscovering(mShown);
-    }
-
-    @Override
     protected void handleClick() {
-        mHost.collapsePanels();
-        mUiHandler.post(mShowDialog);
+        mHandler.postDelayed(new Runnable() {
+            public void run() {
+                mHost.collapsePanels();
+                mUiHandler.post(mShowDialog);
+            }
+        }, FEEDBACK_START_DELAY);
     }
 
     @Override
@@ -82,13 +78,13 @@
         state.visible = true;
         state.label = mContext
                 .getString(R.string.quick_settings_remote_display_no_connection_label);
-        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_cast);
         if (arg instanceof CallbackInfo) {
             final CallbackInfo cb = (CallbackInfo) arg;
             if (cb.connectedRouteName != null) {
                 state.value = !cb.connecting;
             }
         }
+        state.iconId = state.value ? R.drawable.ic_qs_cast_on : R.drawable.ic_qs_cast_off;
     }
 
     private static class CallbackInfo {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 86a4e79..182a0ce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -38,7 +38,6 @@
     public CellularTile(Host host) {
         super(host);
         mController = host.getNetworkController();
-        mController.addNetworkSignalChangedCallback(mCallback);
     }
 
     @Override
@@ -47,8 +46,12 @@
     }
 
     @Override
-    public void dispose() {
-        mController.removeNetworkSignalChangedCallback(mCallback);
+    public void setListening(boolean listening) {
+        if (listening) {
+            mController.addNetworkSignalChangedCallback(mCallback);
+        } else {
+            mController.removeNetworkSignalChangedCallback(mCallback);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 66740af..5301362 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -39,8 +39,6 @@
                 handleRefreshState(value);
             }
         };
-
-        refreshState();
     }
 
     @Override
@@ -49,8 +47,8 @@
     }
 
     @Override
-    public void dispose() {
-        mSetting.dispose();
+    public void setListening(boolean listening) {
+        mSetting.setListening(listening);
     }
 
     @Override
@@ -73,6 +71,6 @@
         state.visible = mVisible;
         state.value = enabled;
         state.label = mContext.getString(R.string.quick_settings_inversion_label);
-        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_invert_colors);
+        state.iconId = R.drawable.ic_qs_color_inversion;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 1a67afc..f2ba558 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -42,7 +42,7 @@
     }
 
     @Override
-    public void dispose() {
+    public void setListening(boolean listening) {
 
     }
 
@@ -55,6 +55,6 @@
     protected void handleUpdateState(State state, Object arg) {
         state.visible = mController != null;
         state.label = mContext.getString(R.string.quick_settings_hotspot_label);
-        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_hotspot);
+        state.iconId = R.drawable.ic_qs_hotspot_off;
     }
 }
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..c5ad9e6 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;
@@ -29,7 +31,6 @@
     public LocationTile(Host host) {
         super(host);
         mController = host.getLocationController();
-        mController.addSettingsChangedCallback(mCallback);
     }
 
     @Override
@@ -37,8 +38,13 @@
         return new BooleanState();
     }
 
-    public void dispose() {
-        mController.removeSettingsChangedCallback(mCallback);
+    @Override
+    public void setListening(boolean listening) {
+        if (listening) {
+            mController.addSettingsChangedCallback(mCallback);
+        } else {
+            mController.removeSettingsChangedCallback(mCallback);
+        }
     }
 
     @Override
@@ -56,16 +62,27 @@
     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_qs_location_on
+                    : R.drawable.ic_qs_location_off);
+            state.icon = d;
+            mUiHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    d.start();
+                }
+            });
+        }
         if (locationEnabled) {
-            state.iconId = R.drawable.ic_qs_location_on;
+            if (state.icon == null) state.iconId = R.drawable.ic_qs_location_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_qs_location_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/qs/tiles/RingerModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
index 36a579c..c5e9b52 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RingerModeTile.java
@@ -33,8 +33,6 @@
     public RingerModeTile(Host host) {
         super(host);
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-        final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
-        mContext.registerReceiver(mReceiver, filter);
     }
 
     @Override
@@ -43,8 +41,13 @@
     }
 
     @Override
-    public void dispose() {
-        mContext.unregisterReceiver(mReceiver);
+    public void setListening(boolean listening) {
+        if (listening) {
+            final IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
+            mContext.registerReceiver(mReceiver, filter);
+        } else {
+            mContext.unregisterReceiver(mReceiver);
+        }
     }
 
     @Override
@@ -64,13 +67,13 @@
         state.visible = true;
         state.value = ringerMode;
         if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
-            state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_vibrate);
+            state.iconId = R.drawable.ic_qs_ringer_vibrate;
             state.label = "Vibrate";
         } else if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
-            state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_silent);
+            state.iconId = R.drawable.ic_qs_ringer_silent;
             state.label = "Silent";
         } else {
-            state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_ringer_audible);
+            state.iconId = R.drawable.ic_qs_ringer_audible;
             state.label = "Audible";
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index d075299..1b0967b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -33,8 +33,6 @@
     public RotationLockTile(Host host) {
         super(host);
         mController = host.getRotationLockController();
-        if (mController == null) return;
-        mController.addRotationLockControllerCallback(mCallback);
     }
 
     @Override
@@ -42,9 +40,13 @@
         return new BooleanState();
     }
 
-    public void dispose() {
+    public void setListening(boolean listening) {
         if (mController == null) return;
-        mController.removeRotationLockControllerCallback(mCallback);
+        if (listening) {
+            mController.addRotationLockControllerCallback(mCallback);
+        } else {
+            mController.removeRotationLockControllerCallback(mCallback);
+        }
     }
 
     @Override
@@ -61,8 +63,8 @@
         if (state.value != rotationLocked) {
             state.value = rotationLocked;
             final AnimationDrawable d = (AnimationDrawable) mContext.getDrawable(rotationLocked
-                    ? R.drawable.ic_rotate_locked_anim
-                    : R.drawable.ic_rotate_unlocked_anim);
+                    ? R.drawable.ic_qs_rotation_locked
+                    : R.drawable.ic_qs_rotation_unlocked);
             state.icon = d;
             mUiHandler.post(new Runnable() {
                 @Override
@@ -80,12 +82,12 @@
                     : R.string.quick_settings_rotation_locked_label;
             state.label = mContext.getString(label);
             if (state.icon == null) {
-                state.icon = mContext.getDrawable(R.drawable.ic_rotate_24_15);
+                state.icon = mContext.getDrawable(R.drawable.ic_qs_rotation_15);
             }
         } else {
             state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
             if (state.icon == null) {
-                state.icon = mContext.getDrawable(R.drawable.ic_rotate_24_01);
+                state.icon = mContext.getDrawable(R.drawable.ic_qs_rotation_01);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index e08a6fa..ef7fb89 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.provider.Settings;
+import android.util.Log;
 
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
@@ -37,7 +38,11 @@
     public WifiTile(Host host) {
         super(host);
         mController = host.getNetworkController();
-        mController.addNetworkSignalChangedCallback(mCallback);
+    }
+
+    @Override
+    public boolean supportsDualTargets() {
+        return true;
     }
 
     @Override
@@ -46,8 +51,12 @@
     }
 
     @Override
-    public void dispose() {
-        mController.removeNetworkSignalChangedCallback(mCallback);
+    public void setListening(boolean listening) {
+        if (listening) {
+            mController.addNetworkSignalChangedCallback(mCallback);
+        } else {
+            mController.removeNetworkSignalChangedCallback(mCallback);
+        }
     }
 
     @Override
@@ -67,8 +76,9 @@
 
     @Override
     protected void handleUpdateState(SignalState state, Object arg) {
-        if (arg == null) return;
         state.visible = true;
+        if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg);
+        if (arg == null) return;
         CallbackInfo cb = (CallbackInfo) arg;
 
         boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null);
@@ -114,6 +124,18 @@
         boolean activityIn;
         boolean activityOut;
         String wifiSignalContentDescription;
+
+        @Override
+        public String toString() {
+            return new StringBuilder("CallbackInfo[")
+                .append("enabled=").append(enabled)
+                .append(",wifiSignalIconId=").append(wifiSignalIconId)
+                .append(",enabledDesc=").append(enabledDesc)
+                .append(",activityIn=").append(activityIn)
+                .append(",activityOut=").append(activityOut)
+                .append(",wifiSignalContentDescription=").append(wifiSignalContentDescription)
+                .append(']').toString();
+        }
     }
 
     private final NetworkSignalChangedCallback mCallback = new NetworkSignalChangedCallback() {
@@ -121,6 +143,7 @@
         public void onWifiSignalChanged(boolean enabled, int wifiSignalIconId,
                 boolean activityIn, boolean activityOut,
                 String wifiSignalContentDescriptionId, String description) {
+            if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled);
             final CallbackInfo info = new CallbackInfo();
             info.enabled = enabled;
             info.wifiSignalIconId = wifiSignalIconId;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
index dceb856..2edefe7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeDetail.java
@@ -32,6 +32,7 @@
 import android.widget.ArrayAdapter;
 import android.widget.CompoundButton;
 import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.RadioButton;
 import android.widget.RelativeLayout;
@@ -39,7 +40,6 @@
 import android.widget.TextView;
 
 import com.android.systemui.R;
-import com.android.systemui.qs.QSImageView;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.ZenModeController;
 
@@ -72,9 +72,7 @@
         mContext = getContext();
         mController = mHost.getZenModeController();
 
-        final QSImageView close = (QSImageView) findViewById(android.R.id.button1);
-        close.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_close));
-        close.setEnabledVersion(true);
+        final ImageView close = (ImageView) findViewById(android.R.id.button1);
         close.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
@@ -239,9 +237,7 @@
             title.setText(condition.summary);
             title.setEnabled(enabled);
             title.setAlpha(enabled ? 1 : .5f);
-            final QSImageView button1 = (QSImageView) row.findViewById(android.R.id.button1);
-            button1.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_minus));
-            button1.setEnabledVersion(true);
+            final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
             button1.setOnClickListener(new OnClickListener() {
                 @Override
                 public void onClick(View v) {
@@ -250,9 +246,7 @@
                 }
             });
 
-            final QSImageView button2 = (QSImageView) row.findViewById(android.R.id.button2);
-            button2.setImageDrawable(mHost.getVectorDrawable(R.drawable.ic_qs_plus));
-            button2.setEnabledVersion(true);
+            final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
             button2.setOnClickListener(new OnClickListener() {
                 @Override
                 public void onClick(View v) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
index 83918e8..bfa9c19 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ZenModeTile.java
@@ -17,6 +17,7 @@
 package com.android.systemui.qs.tiles;
 
 import android.content.Context;
+import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -33,7 +34,6 @@
     public ZenModeTile(Host host) {
         super(host);
         mController = host.getZenModeController();
-        mController.addCallback(mCallback);
     }
 
     @Override
@@ -51,8 +51,12 @@
     }
 
     @Override
-    public void dispose() {
-        mController.removeCallback(mCallback);
+    public void setListening(boolean listening) {
+        if (listening) {
+            mController.addCallback(mCallback);
+        } else {
+            mController.removeCallback(mCallback);
+        }
     }
 
     @Override
@@ -69,14 +73,14 @@
         final boolean zen = arg instanceof Boolean ? (Boolean)arg : mController.isZen();
         state.value = zen;
         state.visible = true;
-        state.iconId = R.drawable.stat_sys_zen_limited;
-        state.icon = mHost.getVectorDrawable(R.drawable.ic_qs_zen);
+        state.iconId = zen ? R.drawable.ic_qs_zen_on : R.drawable.ic_qs_zen_off;
         state.label = mContext.getString(R.string.zen_mode_title);
     }
 
     private final ZenModeController.Callback mCallback = new ZenModeController.Callback() {
         @Override
         public void onZenChanged(boolean zen) {
+            if (DEBUG) Log.d(TAG, "onZenChanged " + zen);
             refreshState(zen);
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Recents.java b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
index d3e949f..00c43e8 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/Recents.java
@@ -43,14 +43,12 @@
     private static final boolean DEBUG = true;
 
     // Which recents to use
-    boolean mUseAlternateRecents;
+    boolean mUseAlternateRecents = true;
     AlternateRecentsComponent mAlternateRecents;
     boolean mBootCompleted = false;
 
     @Override
     public void start() {
-        Configuration config = mContext.getResources().getConfiguration();
-        mUseAlternateRecents = (config.smallestScreenWidthDp < 600);
         if (mUseAlternateRecents) {
             if (mAlternateRecents == null) {
                 mAlternateRecents = new AlternateRecentsComponent(mContext);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index 1ca0476..1c12ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -400,15 +400,14 @@
             ActivityInfo info = ssp.getActivityInfo(t.baseIntent.getComponent(), t.userId);
             if (info == null) continue;
 
-            ActivityManager.RecentsActivityValues av = t.activityValues;
+            ActivityManager.TaskDescription av = t.taskDescription;
             String activityLabel = null;
             BitmapDrawable activityIcon = null;
             int activityColor = 0;
             if (av != null) {
-                activityLabel = (av.label != null ? av.label.toString() :
-                        ssp.getActivityLabel(info));
-                activityIcon = (av.icon != null) ? new BitmapDrawable(res, av.icon) : null;
-                activityColor = av.colorPrimary;
+                activityLabel = (av.getLabel() != null ? av.getLabel() : ssp.getActivityLabel(info));
+                activityIcon = (av.getIcon() != null) ? new BitmapDrawable(res, av.getIcon()) : null;
+                activityColor = av.getPrimaryColor();
             } else {
                 activityLabel = ssp.getActivityLabel(info);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index 8d82883..59d0ea6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -96,18 +96,19 @@
                 int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount;
                 ComponentName cn = new ComponentName("com.android.test" + packageIndex,
                         "com.android.test" + i + ".Activity");
+                String description = "" + i + " - " +
+                        Long.toString(Math.abs(new Random().nextLong()), 36);
                 // Create the recent task info
                 ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
                 rti.id = rti.persistentId = i;
                 rti.baseIntent = new Intent();
                 rti.baseIntent.setComponent(cn);
-                rti.activityValues = new ActivityManager.RecentsActivityValues();
-                rti.description = "" + i + " - " +
-                        Long.toString(Math.abs(new Random().nextLong()), 36);
+                rti.description = description;
                 if (i % 2 == 0) {
-                    rti.activityValues.label = rti.description;
-                    rti.activityValues.icon = Bitmap.createBitmap(mDummyIcon);
-                    rti.activityValues.colorPrimary = new Random().nextInt();
+                    rti.taskDescription = new ActivityManager.TaskDescription(description,
+                        Bitmap.createBitmap(mDummyIcon), new Random().nextInt());
+                } else {
+                    rti.taskDescription = new ActivityManager.TaskDescription();
                 }
                 tasks.add(rti);
             }
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 b079265..7918dec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -429,14 +429,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) {
@@ -903,6 +905,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);
@@ -1065,8 +1068,8 @@
         if (DEBUG) {
             Log.d(TAG, "addNotificationViews: added at " + pos);
         }
-        updateRowStates();
         updateNotificationIcons();
+        updateRowStates();
     }
 
     private void addNotificationViews(IBinder key, StatusBarNotification notification) {
@@ -1086,6 +1089,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);
@@ -1113,6 +1117,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) {
@@ -1120,6 +1128,8 @@
         } else {
             mKeyguardIconOverflowContainer.setVisibility(View.GONE);
         }
+
+        mStackScroller.updateSpeedBumpIndex(speedBumpIndex);
     }
 
     private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
@@ -1335,9 +1345,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/InterceptedNotifications.java b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
index 6401695..9c39002 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/InterceptedNotifications.java
@@ -89,7 +89,7 @@
             return;
         }
         final Notification n = new Notification.Builder(mContext)
-                .setSmallIcon(R.drawable.stat_sys_zen_limited)
+                .setSmallIcon(R.drawable.ic_qs_zen_on)
                 .setContentTitle(mContext.getResources().getQuantityString(
                         R.plurals.zen_mode_notification_title,
                         mIntercepted.size(), mIntercepted.size()))
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/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 869edff..0a3fdef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -60,7 +60,8 @@
         } else if (mDemoMode && command.equals(COMMAND_STATUS)) {
             String volume = args.getString("volume");
             if (volume != null) {
-                int iconId = volume.equals("silent") ? R.drawable.stat_sys_ringer_silent
+                int iconId = volume.equals("zen") ? R.drawable.stat_sys_ringer_zen
+                        : volume.equals("silent") ? R.drawable.stat_sys_ringer_silent
                         : volume.equals("vibrate") ? R.drawable.stat_sys_ringer_vibrate
                         : 0;
                 updateSlot("volume", null, iconId);
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..19252c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -18,6 +18,8 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.util.AttributeSet;
@@ -25,6 +27,7 @@
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
@@ -36,12 +39,11 @@
 import com.android.systemui.statusbar.GestureRecorder;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 public class NotificationPanelView extends PanelView implements
         ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
         View.OnClickListener {
-    public static final boolean DEBUG_GESTURES = true;
-    private static final int EXPANSION_ANIMATION_LENGTH = 375;
 
     PhoneStatusBar mStatusBar;
     private StatusBarHeaderView mHeader;
@@ -80,6 +82,20 @@
     private FlingAnimationUtils mFlingAnimationUtils;
     private int mStatusBarMinHeight;
 
+    private int mClockNotificationsMarginMin;
+    private int mClockNotificationsMarginMax;
+    private float mClockYFractionMin;
+    private float mClockYFractionMax;
+    private Interpolator mFastOutSlowInInterpolator;
+    private ObjectAnimator mClockAnimator;
+    private int mClockAnimationTarget = -1;
+
+    /**
+     * The number (fractional) of notifications the "more" card counts when calculating how many
+     * notifications are currently visible for the y positioning of the clock.
+     */
+    private float mMoreCardNotificationAmount;
+
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -113,9 +129,27 @@
         mNotificationStackScroller = (NotificationStackScrollLayout)
                 findViewById(R.id.notification_stack_scroller);
         mNotificationStackScroller.setOnHeightChangedListener(this);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
+                android.R.interpolator.fast_out_slow_in);
+    }
+
+    @Override
+    protected void loadDimens() {
+        super.loadDimens();
         mNotificationTopPadding = getResources().getDimensionPixelSize(
                 R.dimen.notifications_top_padding);
         mMinStackHeight = getResources().getDimensionPixelSize(R.dimen.collapsed_stack_height);
+        mClockNotificationsMarginMin = getResources().getDimensionPixelSize(
+                R.dimen.keyguard_clock_notifications_margin_min);
+        mClockNotificationsMarginMax = getResources().getDimensionPixelSize(
+                R.dimen.keyguard_clock_notifications_margin_max);
+        mClockYFractionMin =
+                getResources().getFraction(R.fraction.keyguard_clock_y_fraction_min, 1, 1);
+        mClockYFractionMax =
+                getResources().getFraction(R.fraction.keyguard_clock_y_fraction_max, 1, 1);
+        mMoreCardNotificationAmount =
+                (float) getResources().getDimensionPixelSize(R.dimen.notification_summary_height) /
+                        getResources().getDimensionPixelSize(R.dimen.notification_min_height);
         mFlingAnimationUtils = new FlingAnimationUtils(getContext());
         mStatusBarMinHeight = getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.status_bar_height);
@@ -124,15 +158,8 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        int keyguardBottomMargin =
-                ((MarginLayoutParams) mKeyguardStatusView.getLayoutParams()).bottomMargin;
         if (!mQsExpanded) {
-            mStackScrollerIntrinsicPadding = mStatusBar.getBarState() == StatusBarState.KEYGUARD
-                    ? mKeyguardStatusView.getBottom() + keyguardBottomMargin
-                    : mHeader.getBottom() + mNotificationTopPadding;
-            mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding,
-                    mAnimateNextTopPaddingChange);
-            mAnimateNextTopPaddingChange = false;
+            positionClockAndNotifications();
         }
 
         // Calculate quick setting heights.
@@ -143,8 +170,81 @@
         }
     }
 
-    public void animateNextTopPaddingChange() {
+    /**
+     * Positions the clock and notifications dynamically depending on how many notifications are
+     * showing.
+     */
+    private void positionClockAndNotifications() {
+        boolean animateClock = mNotificationStackScroller.isAddOrRemoveAnimationPending();
+        if (mStatusBar.getBarState() != StatusBarState.KEYGUARD) {
+            mStackScrollerIntrinsicPadding = mHeader.getBottom() + mNotificationTopPadding;
+        } else {
+            int notificationCount = mNotificationStackScroller.getNotGoneChildCount();
+            int y = getClockY(notificationCount) - mKeyguardStatusView.getHeight()/2;
+            int padding = getClockNotificationsPadding(notificationCount);
+            if (animateClock || mClockAnimator != null) {
+                startClockAnimation(y);
+            } else {
+                mKeyguardStatusView.setY(y);
+            }
+            mStackScrollerIntrinsicPadding = y + mKeyguardStatusView.getHeight() + padding;
+        }
+        mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding,
+                mAnimateNextTopPaddingChange || animateClock);
+        mAnimateNextTopPaddingChange = false;
+    }
+
+    private void startClockAnimation(int y) {
+        if (mClockAnimationTarget == y) {
+            return;
+        }
+        mClockAnimationTarget = y;
+        getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+            @Override
+            public boolean onPreDraw() {
+                getViewTreeObserver().removeOnPreDrawListener(this);
+                if (mClockAnimator != null) {
+                    mClockAnimator.removeAllListeners();
+                    mClockAnimator.cancel();
+                }
+                mClockAnimator =
+                        ObjectAnimator.ofFloat(mKeyguardStatusView, View.Y, mClockAnimationTarget);
+                mClockAnimator.setInterpolator(mFastOutSlowInInterpolator);
+                mClockAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+                mClockAnimator.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        mClockAnimator = null;
+                        mClockAnimationTarget = -1;
+                    }
+                });
+                StackStateAnimator.startInstantly(mClockAnimator);
+                return true;
+            }
+        });
+    }
+
+    private int getClockNotificationsPadding(int notificationCount) {
+        float t = notificationCount
+                / (mStatusBar.getMaxKeyguardNotifications() + mMoreCardNotificationAmount);
+        t = Math.min(t, 1.0f);
+        return (int) (t * mClockNotificationsMarginMin + (1 - t) * mClockNotificationsMarginMax);
+    }
+
+    private float getClockYFraction(int notificationCount) {
+        float t = notificationCount
+                / (mStatusBar.getMaxKeyguardNotifications() + mMoreCardNotificationAmount);
+        t = Math.min(t, 1.0f);
+        return (1 - t) * mClockYFractionMax + t * mClockYFractionMin;
+    }
+
+    private int getClockY(int notificationCount) {
+        return (int) (getClockYFraction(notificationCount) * getHeight());
+    }
+
+    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..517f763 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;
@@ -321,7 +322,7 @@
         setOnHierarchyChangeListener(mHierarchyListener);
     }
 
-    private void loadDimens() {
+    protected void loadDimens() {
         final Resources res = getContext().getResources();
 
         mSelfExpandVelocityPx = res.getDimension(R.dimen.self_expand_velocity);
@@ -582,10 +583,16 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-
         loadDimens();
     }
 
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        loadDimens();
+        mMaxPanelHeight = -1;
+    }
+
     public void fling(float vel, boolean always) {
         if (DEBUG) logf("fling: vel=%.3f, this=%s", vel, this);
         mVel = vel;
@@ -617,7 +624,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()
@@ -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 842627c..1072e49 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;
@@ -221,8 +223,6 @@
     IconMerger mNotificationIcons;
     // [+>
     View mMoreIcon;
-    // mode indicator icon
-    ImageView mModeIcon;
 
     // expanded notifications
     NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
@@ -486,13 +486,14 @@
     @Override
     public void setZenMode(int mode) {
         super.setZenMode(mode);
-        if (mModeIcon == null) return;
         if (!isDeviceProvisioned()) return;
         final boolean zen = mode != Settings.Global.ZEN_MODE_OFF;
-        mModeIcon.setVisibility(zen ? View.VISIBLE : View.GONE);
         if (!zen) {
             mIntercepted.releaseIntercepted();
         }
+        if (mIconPolicy != null) {
+            mIconPolicy.setZenMode(zen);
+        }
     }
 
     @Override
@@ -616,8 +617,6 @@
         mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
         mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
         mNotificationIcons.setOverflowIndicator(mMoreIcon);
-        mModeIcon = (ImageView)mStatusBarView.findViewById(R.id.modeIcon);
-        mModeIcon.setImageResource(R.drawable.stat_sys_zen_limited);
         mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
         mTickerView = mStatusBarView.findViewById(R.id.ticker);
 
@@ -633,6 +632,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 +1152,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 +1873,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;
     }
@@ -2558,13 +2562,13 @@
                 || (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0;
     }
 
-    public void postStartSettingsActivity(final Intent intent) {
-        mHandler.post(new Runnable() {
+    public void postStartSettingsActivity(final Intent intent, int delay) {
+        mHandler.postDelayed(new Runnable() {
             @Override
             public void run() {
                 handleStartSettingsActivity(intent, true /*onlyProvisioned*/);
             }
-        });
+        }, delay);
     }
 
     private void handleStartSettingsActivity(Intent intent, boolean onlyProvisioned) {
@@ -2580,7 +2584,7 @@
     }
 
     public void startSettingsActivity(String action) {
-        postStartSettingsActivity(new Intent(action));
+        postStartSettingsActivity(new Intent(action), 0);
     }
 
     private static class FastColorDrawable extends Drawable {
@@ -2720,7 +2724,7 @@
         setBarState(StatusBarState.SHADE);
         if (mLeaveOpenOnKeyguardHide) {
             mLeaveOpenOnKeyguardHide = false;
-            mNotificationPanel.animateNextTopPaddingChange();
+            mNotificationPanel.animateToFullShade();
         } else {
             instantCollapseNotificationPanel();
         }
@@ -2892,7 +2896,7 @@
             mLeaveOpenOnKeyguardHide = true;
             showBouncer();
         } else {
-            mNotificationPanel.animateNextTopPaddingChange();
+            mNotificationPanel.animateToFullShade();
             setBarState(StatusBarState.SHADE_LOCKED);
             updateKeyguardState();
         }
@@ -2915,4 +2919,12 @@
     public void reattachSystemIcons() {
         mSystemIconArea.addView(mSystemIcons, 0);
     }
+
+    public void onScreenTurnedOff() {
+        mStackScroller.setAnimationsEnabled(false);
+    }
+
+    public void onScreenTurnedOn() {
+        mStackScroller.setAnimationsEnabled(true);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 194774d..b6f5ae0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -63,6 +63,9 @@
     // ringer volume
     private boolean mVolumeVisible;
 
+    // zen mode
+    private boolean mZen;
+
     // bluetooth device status
     private boolean mBluetoothEnabled = false;
 
@@ -152,6 +155,11 @@
         updateVolume();
     }
 
+    public void setZenMode(boolean zen) {
+        mZen = zen;
+        updateVolume();
+    }
+
     private final void updateAlarm(Intent intent) {
         boolean alarmSet = intent.getBooleanExtra("alarmSet", false);
         mService.setIconVisibility("alarm_clock", alarmSet);
@@ -195,11 +203,15 @@
         AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
         final int ringerMode = audioManager.getRingerMode();
         final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT ||
-                ringerMode == AudioManager.RINGER_MODE_VIBRATE;
+                ringerMode == AudioManager.RINGER_MODE_VIBRATE ||
+                mZen;
 
         final int iconId;
         String contentDescription = null;
-        if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
+        if (mZen) {
+            iconId = R.drawable.stat_sys_ringer_zen;
+            contentDescription = mContext.getString(R.string.zen_mode_title);
+        } else if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
             iconId = R.drawable.stat_sys_ringer_vibrate;
             contentDescription = mContext.getString(R.string.accessibility_ringer_vibrate);
         } else {
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/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 1fe3be5..7029898 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.drawable.VectorDrawable;
 import android.os.HandlerThread;
 import android.os.Looper;
 
@@ -113,7 +112,7 @@
 
     @Override
     public void startSettingsActivity(final Intent intent) {
-        mStatusBar.postStartSettingsActivity(intent);
+        mStatusBar.postStartSettingsActivity(intent, QSTile.FEEDBACK_START_DELAY);
     }
 
     @Override
@@ -137,11 +136,6 @@
     }
 
     @Override
-    public VectorDrawable getVectorDrawable(int resId) {
-        return (VectorDrawable) mContext.getDrawable(resId);
-    }
-
-    @Override
     public BluetoothController getBluetoothController() {
         return mBluetooth;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 2305445..36b063b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -86,6 +86,7 @@
                 (ImageView) findViewById(R.id.brightness_icon),
                 (ToggleSlider) findViewById(R.id.brightness_slider));
         loadDimens();
+        updateVisibilities();
     }
 
     private void loadDimens() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 77b760e..1040c15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -125,11 +125,13 @@
 
     public void onScreenTurnedOff() {
         mScreenOn = false;
+        mPhoneStatusBar.onScreenTurnedOff();
         mBouncer.onScreenTurnedOff();
     }
 
     public void onScreenTurnedOn(final IKeyguardShowCallback callback) {
         mScreenOn = true;
+        mPhoneStatusBar.onScreenTurnedOn();
         if (callback != null) {
             callbackAfterDraw(callback);
         }
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/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 1c7119f..5a19881 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -59,6 +59,7 @@
 
     public void addStateChangedCallback(BluetoothStateChangeCallback cb) {
         mChangeCallbacks.add(cb);
+        fireCallback(cb);
     }
 
     @Override
@@ -131,7 +132,11 @@
 
     private void fireCallbacks() {
         for (BluetoothStateChangeCallback cb : mChangeCallbacks) {
-            cb.onBluetoothStateChange(mEnabled);
+            fireCallback(cb);
         }
     }
+
+    private void fireCallback(BluetoothStateChangeCallback cb) {
+        cb.onBluetoothStateChange(mEnabled);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
index 33a85b1..bcd865c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -28,6 +28,10 @@
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
     private final MediaRouter mMediaRouter;
 
+    private boolean mEnabled;
+    private boolean mConnecting;
+    private String mConnectedRouteName;
+
     public CastControllerImpl(Context context) {
         mMediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
     }
@@ -35,6 +39,7 @@
     @Override
     public void addCallback(Callback callback) {
         mCallbacks.add(callback);
+        fireStateChanged(callback);
     }
 
     @Override
@@ -76,12 +81,23 @@
         if (connectedRoute != null) {
             connectedRouteName = connectedRoute.getName().toString();
         }
-        fireStateChanged(enabled, connecting, connectedRouteName);
+        synchronized(mCallbacks) {
+            mEnabled = enabled;
+            mConnecting = connecting;
+            mConnectedRouteName = connectedRouteName;
+        }
+        fireStateChanged();
     }
 
-    private void fireStateChanged(boolean enabled, boolean connecting, String connectedRouteName) {
+    private void fireStateChanged() {
         for (Callback callback : mCallbacks) {
-            callback.onStateChanged(enabled, connecting, connectedRouteName);
+            fireStateChanged(callback);
+        }
+    }
+
+    private void fireStateChanged(Callback callback) {
+        synchronized(mCallbacks) {
+            callback.onStateChanged(mEnabled, mConnecting, mConnectedRouteName);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Listenable.java
similarity index 82%
rename from packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/policy/Listenable.java
index 158e9c1..4fa59fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Disposable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Listenable.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar.policy;
 
-/** Common interface for items requiring manual cleanup. **/
-public interface Disposable {
-    void dispose();
+/** Common interface for components with an active listening state. **/
+public interface Listenable {
+    void setListening(boolean listening);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
index 9e5ad18..d5b2548 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java
@@ -92,6 +92,7 @@
      */
     public void addSettingsChangedCallback(LocationSettingsChangeCallback cb) {
         mSettingsChangeCallbacks.add(cb);
+        locationSettingsChanged(cb);
     }
 
     public void removeSettingsChangedCallback(LocationSettingsChangeCallback cb) {
@@ -204,6 +205,10 @@
         }
     }
 
+    private void locationSettingsChanged(LocationSettingsChangeCallback cb) {
+        cb.onLocationSettingsChanged(isLocationEnabled());
+    }
+
     @Override
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
index 1eb678d..93c4691 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockController.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.statusbar.policy;
 
-public interface RotationLockController extends Disposable {
+public interface RotationLockController extends Listenable {
     int getRotationLockOrientation();
     boolean isRotationLockAffordanceVisible();
     boolean isRotationLocked();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
index caa07ef..c3bcd94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RotationLockControllerImpl.java
@@ -39,12 +39,12 @@
 
     public RotationLockControllerImpl(Context context) {
         mContext = context;
-        RotationPolicy.registerRotationPolicyListener(mContext,
-                mRotationPolicyListener, UserHandle.USER_ALL);
+        setListening(true);
     }
 
     public void addRotationLockControllerCallback(RotationLockControllerCallback callback) {
         mCallbacks.add(callback);
+        notifyChanged(callback);
     }
 
     public void removeRotationLockControllerCallback(RotationLockControllerCallback callback) {
@@ -68,14 +68,23 @@
     }
 
     @Override
-    public void dispose() {
-        RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener);
+    public void setListening(boolean listening) {
+        if (listening) {
+            RotationPolicy.registerRotationPolicyListener(mContext, mRotationPolicyListener,
+                    UserHandle.USER_ALL);
+        } else {
+            RotationPolicy.unregisterRotationPolicyListener(mContext, mRotationPolicyListener);
+        }
     }
 
     private void notifyChanged() {
         for (RotationLockControllerCallback callback : mCallbacks) {
-            callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext),
-                    RotationPolicy.isRotationLockToggleVisible(mContext));
+            notifyChanged(callback);
         }
     }
+
+    private void notifyChanged(RotationLockControllerCallback callback) {
+        callback.onRotationLockStateChanged(RotationPolicy.isRotationLocked(mContext),
+                RotationPolicy.isRotationLockToggleVisible(mContext));
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index d760f78..adf2935 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -52,6 +52,7 @@
                 fireZenChanged(value != 0);
             }
         };
+        mSetting.setListening(true);
         mNoMan = INotificationManager.Stub.asInterface(
                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
     }
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..58ada75 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;
 
@@ -107,6 +108,7 @@
             = new ArrayList<AnimationEvent>();
     private ArrayList<View> mSwipedOutViews = new ArrayList<View>();
     private final StackStateAnimator mStateAnimator = new StackStateAnimator(this);
+    private boolean mAnimationsEnabled;
 
     /**
      * The raw amount of the overScroll on the top, which is not rubber-banded.
@@ -126,6 +128,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 +248,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;
     }
@@ -333,7 +353,7 @@
             mTopPadding = topPadding;
             updateAlgorithmHeightAndPadding();
             updateContentHeight();
-            if (animate) {
+            if (animate && mAnimationsEnabled && mIsExpanded) {
                 mTopPaddingNeedsAnimation = true;
                 mNeedsAnimation =  true;
             }
@@ -421,9 +441,11 @@
     public void onChildSnappedBack(View animView) {
         mAmbientState.onDragFinished(animView);
         if (!mDragAnimPendingChildren.contains(animView)) {
-            mSnappedBackChildren.add(animView);
+            if (mAnimationsEnabled) {
+                mSnappedBackChildren.add(animView);
+                mNeedsAnimation = true;
+            }
             requestChildrenUpdate();
-            mNeedsAnimation = true;
         } else {
             // We start the swipe and snap back in the same frame, we don't want any animation
             mDragAnimPendingChildren.remove(animView);
@@ -432,10 +454,12 @@
 
     public void onBeginDrag(View v) {
         setSwipingInProgress(true);
-        mDragAnimPendingChildren.add(v);
         mAmbientState.onBeginDrag(v);
+        if (mAnimationsEnabled) {
+            mDragAnimPendingChildren.add(v);
+            mNeedsAnimation = true;
+        }
         requestChildrenUpdate();
-        mNeedsAnimation = true;
     }
 
     public void onDragCancelled(View v) {
@@ -942,6 +966,21 @@
         return null;
     }
 
+    /**
+     * @return the number of children which have visibility unequal to GONE
+     */
+    public int getNotGoneChildCount() {
+        int childCount = getChildCount();
+        int count = 0;
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            if (child.getVisibility() != View.GONE) {
+                count++;
+            }
+        }
+        return count;
+    }
+
     private int getMaxExpandHeight(View view) {
         if (view instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) view;
@@ -1044,8 +1083,11 @@
         mCurrentStackScrollState.removeViewStateForView(child);
         mStackScrollAlgorithm.notifyChildrenChanged(this);
         updateScrollStateForRemovedChild(child);
-        if (mIsExpanded) {
+        generateRemoveAnimation(child);
+    }
 
+    private void generateRemoveAnimation(View child) {
+        if (mIsExpanded && mAnimationsEnabled) {
             if (!mChildrenToAddAnimated.contains(child)) {
                 // Generate Animations
                 mChildrenToRemoveAnimated.add(child);
@@ -1103,8 +1145,17 @@
         }
     }
 
+    public void setAnimationsEnabled(boolean animationsEnabled) {
+        mAnimationsEnabled = animationsEnabled;
+    }
+
+    public boolean isAddOrRemoveAnimationPending() {
+        return mNeedsAnimation
+                && (!mChildrenToAddAnimated.isEmpty() || !mChildrenToRemoveAnimated.isEmpty());
+    }
+
     public void generateAddAnimation(View child) {
-        if (mIsExpanded) {
+        if (mIsExpanded && mAnimationsEnabled) {
 
             // Generate Animations
             mChildrenToAddAnimated.add(child);
@@ -1120,7 +1171,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 +1415,12 @@
     }
 
     public void onExpansionStarted() {
+        mIsExpansionChanging = true;
         mStackScrollAlgorithm.onExpansionStarted(mCurrentStackScrollState);
     }
 
     public void onExpansionStopped() {
+        mIsExpansionChanging = false;
         mStackScrollAlgorithm.onExpansionStopped();
     }
 
@@ -1374,6 +1429,7 @@
         mStackScrollAlgorithm.setIsExpanded(isExpanded);
         if (!isExpanded) {
             mOwnScrollY = 0;
+            mSpeedBumpView.collapse();
         }
     }
 
@@ -1404,7 +1460,7 @@
         mStackScrollAlgorithm.setDimmed(dimmed);
         mAmbientState.setDimmed(dimmed);
         updatePadding(dimmed);
-        if (animate) {
+        if (animate && mAnimationsEnabled) {
             mDimmedNeedsAnimation = true;
             mNeedsAnimation =  true;
         }
@@ -1416,8 +1472,10 @@
      */
     public void setActivatedChild(View activatedChild) {
         mAmbientState.setActivatedChild(activatedChild);
-        mActivateNeedsAnimation = true;
-        mNeedsAnimation =  true;
+        if (mAnimationsEnabled) {
+            mActivateNeedsAnimation = true;
+            mNeedsAnimation =  true;
+        }
         requestChildrenUpdate();
     }
 
@@ -1432,6 +1490,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/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 5ac51f8..a9dcdd6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -434,7 +434,7 @@
     /**
      * Start an animator instantly instead of waiting on the next synchronization frame
      */
-    private void startInstantly(ValueAnimator animator) {
+    public static void startInstantly(ValueAnimator animator) {
         animator.start();
         animator.setCurrentPlayTime(0);
     }
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..2fea785 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -36,11 +36,10 @@
 import com.android.internal.widget.ActionBarContextView;
 import com.android.internal.widget.ActionBarOverlayLayout;
 import com.android.internal.widget.ActionBarView;
+import com.android.internal.widget.DecorContentParent;
 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 +48,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 +56,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 +91,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 +105,6 @@
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
 
 /**
  * Android-specific Window.
@@ -158,7 +148,7 @@
 
     private TextView mTitleView;
 
-    private ActionBarView mActionBar;
+    private DecorContentParent mDecorContentParent;
     private ActionMenuPresenterCallback mActionMenuPresenterCallback;
     private PanelMenuPresenterCallback mPanelMenuPresenterCallback;
 
@@ -213,6 +203,10 @@
     private int mFrameResource = 0;
 
     private int mTextColor = 0;
+    private int mStatusBarColor = 0;
+    private int mNavigationBarColor = 0;
+    private boolean mForcedStatusBarColor = false;
+    private boolean mForcedNavigationBarColor = false;
 
     private CharSequence mTitle = null;
 
@@ -448,8 +442,8 @@
     public void setTitle(CharSequence title) {
         if (mTitleView != null) {
             mTitleView.setText(title);
-        } else if (mActionBar != null) {
-            mActionBar.setWindowTitle(title);
+        } else if (mDecorContentParent != null) {
+            mDecorContentParent.setWindowTitle(title);
         }
         mTitle = title;
     }
@@ -496,10 +490,10 @@
         final boolean isActionBarMenu =
                 (st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR);
 
-        if (isActionBarMenu && mActionBar != null) {
+        if (isActionBarMenu && mDecorContentParent != null) {
             // Enforce ordering guarantees around events so that the action bar never
             // dispatches menu-related events before the panel is prepared.
-            mActionBar.setMenuPrepared();
+            mDecorContentParent.setMenuPrepared();
         }
 
         if (st.createdPanelView == null) {
@@ -511,11 +505,11 @@
                     }
                 }
 
-                if (isActionBarMenu && mActionBar != null) {
+                if (isActionBarMenu && mDecorContentParent != null) {
                     if (mActionMenuPresenterCallback == null) {
                         mActionMenuPresenterCallback = new ActionMenuPresenterCallback();
                     }
-                    mActionBar.setMenu(st.menu, mActionMenuPresenterCallback);
+                    mDecorContentParent.setMenu(st.menu, mActionMenuPresenterCallback);
                 }
 
                 // Call callback, and return if it doesn't want to display menu.
@@ -527,9 +521,9 @@
                     // Ditch the menu created above
                     st.setMenu(null);
 
-                    if (isActionBarMenu && mActionBar != null) {
+                    if (isActionBarMenu && mDecorContentParent != null) {
                         // Don't show it in the action bar either
-                        mActionBar.setMenu(null, mActionMenuPresenterCallback);
+                        mDecorContentParent.setMenu(null, mActionMenuPresenterCallback);
                     }
 
                     return false;
@@ -552,10 +546,10 @@
             }
 
             if (!cb.onPreparePanel(st.featureId, st.createdPanelView, st.menu)) {
-                if (isActionBarMenu && mActionBar != null) {
+                if (isActionBarMenu && mDecorContentParent != null) {
                     // The app didn't want to show the menu for now but it still exists.
                     // Clear it out of the action bar.
-                    mActionBar.setMenu(null, mActionMenuPresenterCallback);
+                    mDecorContentParent.setMenu(null, mActionMenuPresenterCallback);
                 }
                 st.menu.startDispatchingItemsChanged();
                 return false;
@@ -580,7 +574,7 @@
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         // Action bars handle their own menu state
-        if (mActionBar == null) {
+        if (mDecorContentParent == null) {
             PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
             if ((st != null) && (st.menu != null)) {
                 if (st.isOpen) {
@@ -632,12 +626,10 @@
 
     @Override
     public final void openPanel(int featureId, KeyEvent event) {
-        if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
-                mActionBar.isOverflowReserved() &&
+        if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
+                mDecorContentParent.canShowOverflowMenu() &&
                 !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
-            if (mActionBar.getVisibility() == View.VISIBLE) {
-                mActionBar.showOverflowMenu();
-            }
+            mDecorContentParent.showOverflowMenu();
         } else {
             openPanel(getPanelState(featureId, true), event);
         }
@@ -766,10 +758,10 @@
 
     @Override
     public final void closePanel(int featureId) {
-        if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
-                mActionBar.isOverflowReserved() &&
+        if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
+                mDecorContentParent.canShowOverflowMenu() &&
                 !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
-            mActionBar.hideOverflowMenu();
+            mDecorContentParent.hideOverflowMenu();
         } else if (featureId == FEATURE_CONTEXT_MENU) {
             closeContextMenu();
         } else {
@@ -791,7 +783,7 @@
     public final void closePanel(PanelFeatureState st, boolean doCallback) {
         // System.out.println("Close panel: isOpen=" + st.isOpen);
         if (doCallback && st.featureId == FEATURE_OPTIONS_PANEL &&
-                mActionBar != null && mActionBar.isOverflowMenuShowing()) {
+                mDecorContentParent != null && mDecorContentParent.isOverflowMenuShowing()) {
             checkCloseActionMenu(st.menu);
             return;
         }
@@ -837,7 +829,7 @@
         }
 
         mClosingActionMenu = true;
-        mActionBar.dismissPopupMenus();
+        mDecorContentParent.dismissPopups();
         Callback cb = getCallback();
         if (cb != null && !isDestroyed()) {
             cb.onPanelClosed(FEATURE_ACTION_BAR, menu);
@@ -883,7 +875,7 @@
         
         // Prepare the options panel if we have an action bar
         if ((featureId == FEATURE_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL)
-                && mActionBar != null) {
+                && mDecorContentParent != null) {
             st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
             if (st != null) {
                 st.isPrepared = false;
@@ -930,17 +922,15 @@
             
             boolean playSoundEffect = false;
             final PanelFeatureState st = getPanelState(featureId, true);
-            if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null &&
-                    mActionBar.isOverflowReserved() &&
+            if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
+                    mDecorContentParent.canShowOverflowMenu() &&
                     !ViewConfiguration.get(getContext()).hasPermanentMenuKey()) {
-                if (mActionBar.getVisibility() == View.VISIBLE) {
-                    if (!mActionBar.isOverflowMenuShowing()) {
-                        if (!isDestroyed() && preparePanel(st, event)) {
-                            playSoundEffect = mActionBar.showOverflowMenu();
-                        }
-                    } else {
-                        playSoundEffect = mActionBar.hideOverflowMenu();
+                if (!mDecorContentParent.isOverflowMenuShowing()) {
+                    if (!isDestroyed() && preparePanel(st, event)) {
+                        playSoundEffect = mDecorContentParent.showOverflowMenu();
                     }
+                } else {
+                    playSoundEffect = mDecorContentParent.hideOverflowMenu();
                 }
             } else {
                 if (st.isOpen || st.isHandled) {
@@ -1053,7 +1043,7 @@
             st.isHandled = true;
 
             // Only close down the menu if we don't have an action bar keeping it open.
-            if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0 && mActionBar == null) {
+            if ((flags & Menu.FLAG_PERFORM_NO_CLOSE) == 0 && mDecorContentParent == null) {
                 closePanel(st, true);
             }
         }
@@ -1075,7 +1065,7 @@
         boolean res = st.menu.performIdentifierAction(id, flags);
 
         // Only close down the menu if we don't have an action bar keeping it open.
-        if (mActionBar == null) {
+        if (mDecorContentParent == null) {
             closePanel(st, true);
         }
 
@@ -1110,12 +1100,12 @@
     }
 
     private void reopenMenu(boolean toggleMenuMode) {
-        if (mActionBar != null && mActionBar.isOverflowReserved() &&
+        if (mDecorContentParent != null && mDecorContentParent.canShowOverflowMenu() &&
                 (!ViewConfiguration.get(getContext()).hasPermanentMenuKey() ||
-                        mActionBar.isOverflowMenuShowPending())) {
+                        mDecorContentParent.isOverflowMenuShowPending())) {
             final Callback cb = getCallback();
-            if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) {
-                if (cb != null && !isDestroyed() && mActionBar.getVisibility() == View.VISIBLE) {
+            if (!mDecorContentParent.isOverflowMenuShowing() || !toggleMenuMode) {
+                if (cb != null && !isDestroyed()) {
                     // If we have a menu invalidation pending, do it now.
                     if (mInvalidatePanelMenuPosted &&
                             (mInvalidatePanelMenuFeatures & (1 << FEATURE_OPTIONS_PANEL)) != 0) {
@@ -1130,11 +1120,11 @@
                     if (st.menu != null && !st.refreshMenuContent &&
                             cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
                         cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu);
-                        mActionBar.showOverflowMenu();
+                        mDecorContentParent.showOverflowMenu();
                     }
                 }
             } else {
-                mActionBar.hideOverflowMenu();
+                mDecorContentParent.hideOverflowMenu();
                 if (cb != null && !isDestroyed()) {
                     final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
                     cb.onPanelClosed(FEATURE_ACTION_BAR, st.menu);
@@ -1171,7 +1161,7 @@
 
         // If we have an action bar, initialize the menu with a context themed for it.
         if ((st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_ACTION_BAR) &&
-                mActionBar != null) {
+                mDecorContentParent != null) {
             TypedValue outValue = new TypedValue();
             Resources.Theme currentTheme = context.getTheme();
             currentTheme.resolveAttribute(com.android.internal.R.attr.actionBarWidgetTheme,
@@ -1516,8 +1506,8 @@
         mIconRes = resId;
         mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON;
         mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK;
-        if (mActionBar != null) {
-            mActionBar.setIcon(resId);
+        if (mDecorContentParent != null) {
+            mDecorContentParent.setIcon(resId);
         }
     }
 
@@ -1527,13 +1517,14 @@
             return;
         }
         mIconRes = resId;
-        if (mActionBar != null && (!mActionBar.hasIcon() ||
+        if (mDecorContentParent != null && (!mDecorContentParent.hasIcon() ||
                 (mResourcesSetFlags & FLAG_RESOURCE_SET_ICON_FALLBACK) != 0)) {
             if (resId != 0) {
-                mActionBar.setIcon(resId);
+                mDecorContentParent.setIcon(resId);
                 mResourcesSetFlags &= ~FLAG_RESOURCE_SET_ICON_FALLBACK;
             } else {
-                mActionBar.setIcon(getContext().getPackageManager().getDefaultActivityIcon());
+                mDecorContentParent.setIcon(
+                        getContext().getPackageManager().getDefaultActivityIcon());
                 mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
             }
         }
@@ -1543,8 +1534,8 @@
     public void setLogo(int resId) {
         mLogoRes = resId;
         mResourcesSetFlags |= FLAG_RESOURCE_SET_LOGO;
-        if (mActionBar != null) {
-            mActionBar.setLogo(resId);
+        if (mDecorContentParent != null) {
+            mDecorContentParent.setLogo(resId);
         }
     }
 
@@ -1554,8 +1545,8 @@
             return;
         }
         mLogoRes = resId;
-        if (mActionBar != null && !mActionBar.hasLogo()) {
-            mActionBar.setLogo(resId);
+        if (mDecorContentParent != null && !mDecorContentParent.hasLogo()) {
+            mDecorContentParent.setLogo(resId);
         }
     }
 
@@ -1812,9 +1803,9 @@
             outState.putSparseParcelableArray(PANELS_TAG, panelStates);
         }
 
-        if (mActionBar != null) {
+        if (mDecorContentParent != null) {
             SparseArray<Parcelable> actionBarStates = new SparseArray<Parcelable>();
-            mActionBar.saveHierarchyState(actionBarStates);
+            mDecorContentParent.saveToolbarHierarchyState(actionBarStates);
             outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates);
         }
 
@@ -1853,11 +1844,11 @@
             restorePanelState(panelStates);
         }
 
-        if (mActionBar != null) {
+        if (mDecorContentParent != null) {
             SparseArray<Parcelable> actionBarStates =
                     savedInstanceState.getSparseParcelableArray(ACTION_BAR_TAG);
             if (actionBarStates != null) {
-                mActionBar.restoreHierarchyState(actionBarStates);
+                mDecorContentParent.restoreToolbarHierarchyState(actionBarStates);
             } else {
                 Log.w(TAG, "Missing saved instance states for action bar views! " +
                         "State will not be restored.");
@@ -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;
@@ -2122,12 +2122,7 @@
         }
 
         public boolean superDispatchKeyEvent(KeyEvent event) {
-            if (super.dispatchKeyEvent(event)) {
-                return true;
-            }
-
-            // Not handled by the view hierarchy, does the action bar want it
-            // to cancel out of something special?
+            // Give priority to closing action modes if applicable.
             if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                 final int action = event.getAction();
                 // Back cancels action modes first.
@@ -2137,17 +2132,9 @@
                     }
                     return true;
                 }
-
-                // Next collapse any expanded action views.
-                if (mActionBar != null && mActionBar.hasExpandedActionView()) {
-                    if (action == KeyEvent.ACTION_UP) {
-                        mActionBar.collapseActionView();
-                    }
-                    return true;
-                }
             }
 
-            return false;
+            return super.dispatchKeyEvent(event);
         }
 
         public boolean superDispatchKeyShortcutEvent(KeyEvent event) {
@@ -2582,8 +2569,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 +2591,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 +2656,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 +2703,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 {
@@ -2789,8 +2829,8 @@
                 cb.onDetachedFromWindow();
             }
 
-            if (mActionBar != null) {
-                mActionBar.dismissPopupMenus();
+            if (mDecorContentParent != null) {
+                mDecorContentParent.dismissPopups();
             }
 
             if (mActionModePopup != null) {
@@ -3009,6 +3049,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 +3059,25 @@
         } 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);
+        }
+        if (!mForcedStatusBarColor) {
+            mStatusBarColor = a.getColor(R.styleable.Window_statusBarColor, 0xFF000000);
+        }
+        if (!mForcedNavigationBarColor) {
+            mNavigationBarColor = a.getColor(R.styleable.Window_navigationBarColor, 0xFF000000);
+        }
+
         if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
                 >= android.os.Build.VERSION_CODES.HONEYCOMB) {
             if (a.getBoolean(
@@ -3207,96 +3266,68 @@
             // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
             mDecor.makeOptionalFitsSystemWindows();
 
-            mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
-            if (mTitleView != null) {
-                mTitleView.setLayoutDirection(mDecor.getLayoutDirection());
-                if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
-                    View titleContainer = findViewById(com.android.internal.R.id.title_container);
-                    if (titleContainer != null) {
-                        titleContainer.setVisibility(View.GONE);
-                    } else {
-                        mTitleView.setVisibility(View.GONE);
-                    }
-                    if (mContentParent instanceof FrameLayout) {
-                        ((FrameLayout)mContentParent).setForeground(null);
-                    }
-                } else {
-                    mTitleView.setText(mTitle);
+            final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
+                    com.android.internal.R.id.decor_content_parent);
+
+            if (decorContentParent != null) {
+                mDecorContentParent = decorContentParent;
+                mDecorContentParent.setWindowCallback(getCallback());
+                if (mDecorContentParent.getTitle() == null) {
+                    mDecorContentParent.setWindowTitle(mTitle);
                 }
-            } else {
-                mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
-                if (mActionBar != null) {
-                    mActionBar.setWindowCallback(getCallback());
-                    if (mActionBar.getTitle() == null) {
-                        mActionBar.setWindowTitle(mTitle);
-                    }
-                    final int localFeatures = getLocalFeatures();
-                    if ((localFeatures & (1 << FEATURE_PROGRESS)) != 0) {
-                        mActionBar.initProgress();
-                    }
-                    if ((localFeatures & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
-                        mActionBar.initIndeterminateProgress();
-                    }
 
-                    final ActionBarOverlayLayout abol = (ActionBarOverlayLayout) findViewById(
-                            com.android.internal.R.id.action_bar_overlay_layout);
-                    if (abol != null) {
-                        abol.setOverlayMode(
-                                (localFeatures & (1 << FEATURE_ACTION_BAR_OVERLAY)) != 0);
+                final int localFeatures = getLocalFeatures();
+                for (int i = 0; i < FEATURE_MAX; i++) {
+                    if ((localFeatures & (1 << i)) != 0) {
+                        mDecorContentParent.initFeature(i);
                     }
+                }
 
-                    boolean splitActionBar = false;
-                    final boolean splitWhenNarrow =
-                            (mUiOptions & ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW) != 0;
-                    if (splitWhenNarrow) {
-                        splitActionBar = getContext().getResources().getBoolean(
-                                com.android.internal.R.bool.split_action_bar_is_narrow);
-                    } else {
-                        splitActionBar = getWindowStyle().getBoolean(
-                                com.android.internal.R.styleable.Window_windowSplitActionBar, false);
-                    }
-                    final ActionBarContainer splitView = (ActionBarContainer) findViewById(
-                            com.android.internal.R.id.split_action_bar);
-                    if (splitView != null) {
-                        mActionBar.setSplitView(splitView);
-                        mActionBar.setSplitActionBar(splitActionBar);
-                        mActionBar.setSplitWhenNarrow(splitWhenNarrow);
+                mDecorContentParent.setUiOptions(mUiOptions);
 
-                        final ActionBarContextView cab = (ActionBarContextView) findViewById(
-                                com.android.internal.R.id.action_context_bar);
-                        cab.setSplitView(splitView);
-                        cab.setSplitActionBar(splitActionBar);
-                        cab.setSplitWhenNarrow(splitWhenNarrow);
-                    } else if (splitActionBar) {
-                        Log.e(TAG, "Requested split action bar with " +
-                                "incompatible window decor! Ignoring request.");
-                    }
+                if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
+                        (mIconRes != 0 && !mDecorContentParent.hasIcon())) {
+                    mDecorContentParent.setIcon(mIconRes);
+                } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
+                        mIconRes == 0 && !mDecorContentParent.hasIcon()) {
+                    mDecorContentParent.setIcon(
+                            getContext().getPackageManager().getDefaultActivityIcon());
+                    mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
+                }
+                if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
+                        (mLogoRes != 0 && !mDecorContentParent.hasLogo())) {
+                    mDecorContentParent.setLogo(mLogoRes);
+                }
 
-                    if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
-                            (mIconRes != 0 && !mActionBar.hasIcon())) {
-                        mActionBar.setIcon(mIconRes);
-                    } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
-                            mIconRes == 0 && !mActionBar.hasIcon()) {
-                        mActionBar.setIcon(
-                                getContext().getPackageManager().getDefaultActivityIcon());
-                        mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
-                    }
-                    if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
-                            (mLogoRes != 0 && !mActionBar.hasLogo())) {
-                        mActionBar.setLogo(mLogoRes);
-                    }
-
-                    // Post the panel invalidate for later; avoid application onCreateOptionsMenu
-                    // being called in the middle of onCreate or similar.
-                    mDecor.post(new Runnable() {
-                        public void run() {
-                            // Invalidate if the panel menu hasn't been created before this.
-                            PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
-                            if (!isDestroyed() && (st == null || st.menu == null)) {
-                                invalidatePanelMenu(FEATURE_ACTION_BAR);
-                            }
+                // Post the panel invalidate for later; avoid application onCreateOptionsMenu
+                // being called in the middle of onCreate or similar.
+                mDecor.post(new Runnable() {
+                    public void run() {
+                        // Invalidate if the panel menu hasn't been created before this.
+                        PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
+                        if (!isDestroyed() && (st == null || st.menu == null)) {
+                            invalidatePanelMenu(FEATURE_ACTION_BAR);
                         }
-                    });
+                    }
+                });
+            } else {
+                mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
+                if (mTitleView != null) {
+                    mTitleView.setLayoutDirection(mDecor.getLayoutDirection());
+                    if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
+                        View titleContainer = findViewById(
+                                com.android.internal.R.id.title_container);
+                        if (titleContainer != null) {
+                            titleContainer.setVisibility(View.GONE);
+                        } else {
+                            mTitleView.setVisibility(View.GONE);
+                        }
+                        if (mContentParent instanceof FrameLayout) {
+                            ((FrameLayout)mContentParent).setForeground(null);
+                        }
+                    } else {
+                        mTitleView.setText(mTitle);
+                    }
                 }
             }
 
@@ -3522,6 +3553,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 +4205,32 @@
     void sendCloseSystemWindows(String reason) {
         PhoneWindowManager.sendCloseSystemWindows(getContext(), reason);
     }
+
+    @Override
+    public int getStatusBarColor() {
+        return mStatusBarColor;
+    }
+
+    @Override
+    public void setStatusBarColor(int color) {
+        mStatusBarColor = color;
+        mForcedStatusBarColor = true;
+        if (mDecor != null) {
+            mDecor.updateColorViews(null);
+        }
+    }
+
+    @Override
+    public int getNavigationBarColor() {
+        return mNavigationBarColor;
+    }
+
+    @Override
+    public void setNavigationBarColor(int color) {
+        mNavigationBarColor = color;
+        mForcedNavigationBarColor = true;
+        if (mDecor != null) {
+            mDecor.updateColorViews(null);
+        }
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 43c7391..466c8ed 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
@@ -1316,6 +1317,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() {
@@ -2682,7 +2690,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;
@@ -2808,7 +2817,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
@@ -3004,12 +3014,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;
@@ -5206,7 +5220,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..01af753 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -193,6 +193,9 @@
     private static final boolean DBG = true;
     private static final boolean VDBG = true; // STOPSHIP
 
+    // network sampling debugging
+    private static final boolean SAMPLE_DBG = false;
+
     private static final boolean LOGD_RULES = false;
 
     // TODO: create better separation between radio types and network types
@@ -219,10 +222,10 @@
     // Set network sampling interval at 12 minutes, this way, even if the timers get
     // aggregated, it will fire at around 15 minutes, which should allow us to
     // aggregate this timer with other timers (specially the socket keep alive timers)
-    private static final int DEFAULT_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 12 * 60);
+    private static final int DEFAULT_SAMPLING_INTERVAL_IN_SECONDS = (SAMPLE_DBG ? 30 : 12 * 60);
 
     // start network sampling a minute after booting ...
-    private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 60);
+    private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (SAMPLE_DBG ? 30 : 60);
 
     AlarmManager mAlarmManager;
 
@@ -504,10 +507,14 @@
 
     TelephonyManager mTelephonyManager;
 
+    // sequence number for Networks
     private final static int MIN_NET_ID = 10; // some reserved marks
     private final static int MAX_NET_ID = 65535;
     private int mNextNetId = MIN_NET_ID;
 
+    // sequence number of NetworkRequests
+    private int mNextNetworkRequestId = 1;
+
     public ConnectivityService(Context context, INetworkManagementService netd,
             INetworkStatsService statsService, INetworkPolicyManager policyManager) {
         // Currently, omitting a NetworkFactory will create one internally
@@ -523,7 +530,7 @@
         NetworkCapabilities netCap = new NetworkCapabilities();
         netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
         netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
-        mDefaultRequest = new NetworkRequest(netCap, true);
+        mDefaultRequest = new NetworkRequest(netCap, true, nextNetworkRequestId());
         NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(),
                 NetworkRequestInfo.REQUEST);
         mNetworkRequests.put(mDefaultRequest, nri);
@@ -770,6 +777,10 @@
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
     }
 
+    private synchronized int nextNetworkRequestId() {
+        return mNextNetworkRequestId++;
+    }
+
     private synchronized int nextNetId() {
         int netId = mNextNetId;
         if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID;
@@ -3216,6 +3227,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 " +
@@ -5267,7 +5279,7 @@
             throw new IllegalArgumentException("Bad timeout specified");
         }
         NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
-                networkCapabilities));
+                networkCapabilities), false, nextNetworkRequestId());
         if (DBG) log("requestNetwork for " + networkRequest);
         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
                 NetworkRequestInfo.REQUEST);
@@ -5293,7 +5305,7 @@
         enforceAccessPermission();
 
         NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities(
-                networkCapabilities));
+                networkCapabilities), false, nextNetworkRequestId());
         if (DBG) log("listenForNetwork for " + networkRequest);
         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
                 NetworkRequestInfo.LISTEN);
@@ -5491,10 +5503,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 +5641,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/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 0b9570d..50553ee 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -2369,20 +2369,20 @@
 
     void setEnabledSessionInMainThread(SessionState session) {
         if (mEnabledSession != session) {
-            if (mEnabledSession != null) {
+            if (mEnabledSession != null && mEnabledSession.session != null) {
                 try {
                     if (DEBUG) Slog.v(TAG, "Disabling: " + mEnabledSession);
-                    mEnabledSession.method.setSessionEnabled(
-                            mEnabledSession.session, false);
+                    mEnabledSession.method.setSessionEnabled(mEnabledSession.session, false);
                 } catch (RemoteException e) {
                 }
             }
             mEnabledSession = session;
-            try {
-                if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
-                session.method.setSessionEnabled(
-                        session.session, true);
-            } catch (RemoteException e) {
+            if (mEnabledSession != null && mEnabledSession.session != null) {
+                try {
+                    if (DEBUG) Slog.v(TAG, "Enabling: " + mEnabledSession);
+                    mEnabledSession.method.setSessionEnabled(mEnabledSession.session, true);
+                } catch (RemoteException e) {
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bab5b9c..7abc75f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7087,50 +7087,7 @@
         rti.description = tr.lastDescription;
         rti.stackId = tr.stack.mStackId;
         rti.userId = tr.userId;
-
-        // Traverse upwards looking for any break between main task activities and
-        // utility activities.
-        final ArrayList<ActivityRecord> activities = tr.mActivities;
-        int activityNdx;
-        final int numActivities = activities.size();
-        for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
-             ++activityNdx) {
-            final ActivityRecord r = activities.get(activityNdx);
-            if (r.intent != null &&
-                    (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
-                            != 0) {
-                break;
-            }
-        }
-        if (activityNdx > 0) {
-            // Traverse downwards starting below break looking for set label, icon.
-            // Note that if there are activities in the task but none of them set the
-            // recent activity values, then we do not fall back to the last set
-            // values in the TaskRecord.
-            rti.activityValues = new ActivityManager.RecentsActivityValues();
-            for (--activityNdx; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = activities.get(activityNdx);
-                if (r.activityValues != null) {
-                    if (rti.activityValues.label == null) {
-                        rti.activityValues.label = r.activityValues.label;
-                        tr.lastActivityValues.label = r.activityValues.label;
-                    }
-                    if (rti.activityValues.icon == null) {
-                        rti.activityValues.icon = r.activityValues.icon;
-                        tr.lastActivityValues.icon = r.activityValues.icon;
-                    }
-                    if (rti.activityValues.colorPrimary == 0) {
-                        rti.activityValues.colorPrimary = r.activityValues.colorPrimary;
-                        tr.lastActivityValues.colorPrimary = r.activityValues.colorPrimary;
-                    }
-                }
-            }
-        } else {
-            // If there are no activity records in this task, then we use the last
-            // resolved values
-            rti.activityValues =
-                    new ActivityManager.RecentsActivityValues(tr.lastActivityValues);
-        }
+        rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription);
         return rti;
     }
 
@@ -7261,11 +7218,12 @@
     }
 
     @Override
-    public void setRecentsActivityValues(IBinder token, ActivityManager.RecentsActivityValues rav) {
+    public void setTaskDescription(IBinder token, ActivityManager.TaskDescription td) {
         synchronized (this) {
             ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
-                r.activityValues = rav;
+                r.taskDescription = td;
+                r.task.updateTaskDescription();
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 9582ac7..dbe2ca1 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -149,7 +149,7 @@
     boolean mStartingWindowShown = false;
     ActivityContainer mInitialActivityContainer;
 
-    ActivityManager.RecentsActivityValues activityValues; // the recents information for this activity
+    ActivityManager.TaskDescription taskDescription; // the recents information for this activity
 
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index c1e5e5b..33e59a7 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -742,19 +742,10 @@
         int w = mThumbnailWidth;
         int h = mThumbnailHeight;
         if (w < 0) {
-            Configuration config = res.getConfiguration();
-            boolean useAlternateRecents = (config.smallestScreenWidthDp < 600);
-            if (useAlternateRecents) {
-                mThumbnailWidth = w =
-                   res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width);
-                mThumbnailHeight = h =
-                   res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_height);
-            } else {
-                mThumbnailWidth = w =
-                    res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
-                mThumbnailHeight = h =
-                    res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
-            }
+            mThumbnailWidth = w =
+               res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_width);
+            mThumbnailHeight = h =
+               res.getDimensionPixelSize(com.android.internal.R.dimen.recents_thumbnail_height);
         }
 
         if (w > 0) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 5d744e6..ef9c711 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1816,7 +1816,7 @@
             }
             targetStack = sourceTask.stack;
             targetStack.moveToFront();
-            mWindowManager.moveTaskToTop(sourceTask.taskId);
+            mWindowManager.moveTaskToTop(targetStack.topTask().taskId);
             if (!addingToTask &&
                     (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
                 // In this case, we are adding the activity to an existing
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/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index be884e7..6d66b29 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -58,8 +58,8 @@
 
     // This represents the last resolved activity values for this task
     // NOTE: This value needs to be persisted with each task
-    ActivityManager.RecentsActivityValues lastActivityValues =
-            new ActivityManager.RecentsActivityValues();
+    ActivityManager.TaskDescription lastTaskDescription =
+            new ActivityManager.TaskDescription();
 
     /** List of all activities in the task arranged in history order */
     final ArrayList<ActivityRecord> mActivities = new ArrayList<ActivityRecord>();
@@ -486,6 +486,48 @@
         return null;
     }
 
+    /** Updates the last task description values. */
+    void updateTaskDescription() {
+        // Traverse upwards looking for any break between main task activities and
+        // utility activities.
+        int activityNdx;
+        final int numActivities = mActivities.size();
+        for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
+             ++activityNdx) {
+            final ActivityRecord r = mActivities.get(activityNdx);
+            if (r.intent != null &&
+                    (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
+                            != 0) {
+                break;
+            }
+        }
+        if (activityNdx > 0) {
+            // Traverse downwards starting below break looking for set label, icon.
+            // Note that if there are activities in the task but none of them set the
+            // recent activity values, then we do not fall back to the last set
+            // values in the TaskRecord.
+            String label = null;
+            Bitmap icon = null;
+            int colorPrimary = 0;
+            for (--activityNdx; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = mActivities.get(activityNdx);
+                if (r.taskDescription != null) {
+                    if (label == null) {
+                        label = r.taskDescription.getLabel();
+                    }
+                    if (icon == null) {
+                        icon = r.taskDescription.getIcon();
+                    }
+                    if (colorPrimary == 0) {
+                        colorPrimary = r.taskDescription.getPrimaryColor();
+
+                    }
+                }
+            }
+            lastTaskDescription = new ActivityManager.TaskDescription(label, icon, colorPrimary);
+        }
+    }
+
     void dump(PrintWriter pw, String prefix) {
         if (numActivities != 0 || rootWasReset || userId != 0 || numFullscreen != 0) {
             pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
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/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 5327ef4..986cb9b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -24,6 +24,7 @@
 import android.os.Message;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 
 import libcore.util.EmptyArray;
 
@@ -79,11 +80,12 @@
             new SparseArray<HdmiCecDeviceInfo>();
     // Set-like container for all local devices' logical address.
     // Key and value are same.
-    private final SparseArray<Integer> mLocalLogicalAddresses =
-            new SparseArray<Integer>();
+    private final SparseIntArray mLocalAddresses = new SparseIntArray();
 
     // Private constructor.  Use HdmiCecController.create().
     private HdmiCecController() {
+        // TODO: Consider restoring the local device addresses from persistent storage
+        //       to allocate the same addresses again if possible.
     }
 
     /**
@@ -109,6 +111,44 @@
     }
 
     /**
+     * Initialize {@link #mLocalAddresses} by allocating logical addresses for each hosted type.
+     *
+     * @param deviceTypes local device types
+     */
+    void initializeLocalDevices(int[] deviceTypes) {
+        for (int deviceType : deviceTypes) {
+            int preferred = getPreferredAddress(deviceType);
+            allocateLogicalAddress(deviceType, preferred, new AllocateLogicalAddressCallback() {
+                @Override
+                public void onAllocated(int deviceType, int logicalAddress) {
+                    addLogicalAddress(logicalAddress);
+                }
+            });
+        }
+    }
+
+    /**
+     * Get the preferred address for a given type.
+     *
+     * @param deviceType logical device type to get the address for
+     * @return preferred address; {@link HdmiCec#ADDR_UNREGISTERED} if not available.
+     */
+    private int getPreferredAddress(int deviceType) {
+        // Uses the data restored from persistent memory at boot up if they are available.
+        // Otherwise we return UNREGISTERED indicating there is no preferred address.
+        // Note that for address SPECIFIC_USE(14), HdmiCec.getTypeFromAddress() returns DEVICE_TV,
+        // meaning that we do not support device type video processor yet.
+        for (int i = 0; i < mLocalAddresses.size(); ++i) {
+            int address = mLocalAddresses.keyAt(i);
+            int type = HdmiCec.getTypeFromAddress(address);
+            if (type == deviceType) {
+                return address;
+            }
+        }
+        return HdmiCec.ADDR_UNREGISTERED;
+    }
+
+    /**
      * Interface to report allocated logical address.
      */
     interface AllocateLogicalAddressCallback {
@@ -322,7 +362,7 @@
      */
     int addLogicalAddress(int newLogicalAddress) {
         if (HdmiCec.isValidAddress(newLogicalAddress)) {
-            mLocalLogicalAddresses.append(newLogicalAddress, newLogicalAddress);
+            mLocalAddresses.put(newLogicalAddress, newLogicalAddress);
             return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
         } else {
             return -1;
@@ -337,7 +377,7 @@
     void clearLogicalAddress() {
         // TODO: consider to backup logical address so that new logical address
         // allocation can use it as preferred address.
-        mLocalLogicalAddresses.clear();
+        mLocalAddresses.clear();
         nativeClearLogicalAddress(mNativePtr);
     }
 
@@ -382,7 +422,7 @@
         // Can access command targeting devices available in local device or
         // broadcast command.
         return address == HdmiCec.ADDR_BROADCAST
-                || mLocalLogicalAddresses.get(address) != null;
+                || mLocalAddresses.indexOfKey(address) < 0;
     }
 
     private void onReceiveCommand(HdmiCecMessage message) {
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..7c136db 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -54,7 +54,10 @@
     @Override
     public void onStart() {
         mCecController = HdmiCecController.create(this);
-        if (mCecController == null) {
+        if (mCecController != null) {
+            mCecController.initializeLocalDevices(getContext().getResources()
+                    .getIntArray(com.android.internal.R.array.config_hdmiCecLogicalDeviceType));
+        } else {
             Slog.i(TAG, "Device does not support HDMI-CEC.");
         }
 
@@ -127,8 +130,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 +173,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 cf1d95a..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/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f9eabcd..61b3a89 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1663,7 +1663,10 @@
             updateAllSharedLibrariesLPw();
 
             for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
-                adjustCpuAbisForSharedUserLPw(setting.packages, true /* do dexopt */,
+                // NOTE: We ignore potential failures here during a system scan (like
+                // the rest of the commands above) because there's precious little we
+                // can do about it. A settings error is reported, though.
+                adjustCpuAbisForSharedUserLPw(setting.packages, null,
                         false /* force dexopt */, false /* defer dexopt */);
             }
 
@@ -5613,8 +5616,12 @@
             if ((scanMode&SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
                 // We don't do this here during boot because we can do it all
                 // at once after scanning all existing packages.
-                adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages,
-                        true, forceDex, (scanMode & SCAN_DEFER_DEX) != 0);
+                if (!adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages,
+                        pkg.applicationInfo.cpuAbi,
+                        forceDex, (scanMode & SCAN_DEFER_DEX) != 0)) {
+                    mLastScanError = PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE;
+                    return null;
+                }
             }
             // We don't expect installation to fail beyond this point,
             if ((scanMode&SCAN_MONITOR) != 0) {
@@ -5960,9 +5967,8 @@
         return pkg;
     }
 
-    public void adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser,
-            boolean doDexOpt, boolean forceDexOpt, boolean deferDexOpt) {
-        String requiredInstructionSet = null;
+    private boolean adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser,
+            String requiredInstructionSet, boolean forceDexOpt, boolean deferDexOpt) {
         PackageSetting requirer = null;
         for (PackageSetting ps : packagesForUser) {
             if (ps.cpuAbiString != null) {
@@ -5970,20 +5976,16 @@
                 if (requiredInstructionSet != null) {
                     if (!instructionSet.equals(requiredInstructionSet)) {
                         // We have a mismatch between instruction sets (say arm vs arm64).
-                        //
-                        // TODO: We should rescan all the packages in a shared UID to check if
-                        // they do contain shared libs for other ABIs in addition to the ones we've
-                        // already extracted. For example, the package might contain both arm64-v8a
-                        // and armeabi-v7a shared libs, and we'd have chosen arm64-v8a on 64 bit
-                        // devices.
-                        String errorMessage = "Instruction set mismatch, " + requirer.pkg.packageName
-                                + " requires " + requiredInstructionSet + " whereas " + ps.pkg.packageName
+                        // bail out.
+                        String errorMessage = "Instruction set mismatch, "
+                                + ((requirer == null) ? "[caller]" : requirer.pkg)
+                                + " requires " + requiredInstructionSet + " whereas " + ps.pkg
                                 + " requires " + instructionSet;
                         Slog.e(TAG, errorMessage);
 
                         reportSettingsProblem(Log.WARN, errorMessage);
                         // Give up, don't bother making any other changes to the package settings.
-                        return;
+                        return false;
                     }
                 } else {
                     requiredInstructionSet = instructionSet;
@@ -5999,14 +6001,20 @@
                     if (ps.pkg != null) {
                         ps.pkg.applicationInfo.cpuAbi = requirer.cpuAbiString;
                         Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + ps.cpuAbiString);
-                        if (doDexOpt) {
-                            performDexOptLI(ps.pkg, forceDexOpt, deferDexOpt, true);
+
+                        if (performDexOptLI(ps.pkg, forceDexOpt, deferDexOpt, true) == DEX_OPT_FAILED) {
+                            ps.cpuAbiString = null;
+                            ps.pkg.applicationInfo.cpuAbi = null;
+                            return false;
+                        } else {
                             mInstaller.rmdex(ps.codePathString, getPreferredInstructionSet());
                         }
                     }
                 }
             }
         }
+
+        return true;
     }
 
     private void setUpCustomResolverActivity(PackageParser.Package pkg) {
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/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 99ec242..c20e38c 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -679,7 +679,7 @@
 
     Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
                             int appWidth, int appHeight, int orientation,
-                            Rect containingFrame, Rect contentInsets, Configuration configuration) {
+                            Rect containingFrame, Rect contentInsets) {
         Animation a;
         if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
             a = loadAnimation(mNextAppTransitionPackage, enter ?
@@ -700,15 +700,9 @@
                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
             mNextAppTransitionScaleUp =
                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
-            boolean useAlternateThumbnailAnimation = (configuration.smallestScreenWidthDp < 600);
-            if (useAlternateThumbnailAnimation) {
-                a = createAlternateThumbnailEnterExitAnimationLocked(
-                        getThumbnailTransitionState(enter), appWidth, appHeight, orientation,
-                        transit, containingFrame, contentInsets);
-            } else {
-                a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
-                        appWidth, appHeight, transit);
-            }
+            a = createAlternateThumbnailEnterExitAnimationLocked(
+                    getThumbnailTransitionState(enter), appWidth, appHeight, orientation,
+                    transit, containingFrame, contentInsets);
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                 String animName = mNextAppTransitionScaleUp ?
                         "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 836a19c..c6fffbf 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;
 
@@ -3190,7 +3194,7 @@
             }
 
             Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
-                    mCurConfiguration.orientation, containingFrame, contentInsets, mCurConfiguration);
+                    mCurConfiguration.orientation, containingFrame, contentInsets);
             if (a != null) {
                 if (DEBUG_ANIM) {
                     RuntimeException e = null;
@@ -8673,7 +8677,7 @@
                 wtoken.deferClearAllDrawn = false;
             }
 
-            boolean useAlternateThumbnailAnimation = (mCurConfiguration.smallestScreenWidthDp < 600);
+            boolean useAlternateThumbnailAnimation = true;
             AppWindowAnimator appAnimator =
                     topOpeningApp == null ? null : topOpeningApp.mAppAnimator;
             Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 3c9d53e..1e79dcb 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -46,6 +46,7 @@
 import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
+import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
 import android.view.WindowManager.LayoutParams;
@@ -151,6 +152,10 @@
     static final int READY_TO_SHOW = 3;
     /** Set when the window has been shown in the screen the first time. */
     static final int HAS_DRAWN = 4;
+
+    private static final int SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN =
+            View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+
     static String drawStateToString(int state) {
         switch (state) {
             case NO_SURFACE: return "NO_SURFACE";
@@ -1176,9 +1181,15 @@
             // content insets as well.
             int offsetTop = Math.max(w.mSystemDecorRect.top, w.mContentInsets.top);
             mTmpClipRect.set(w.mSystemDecorRect);
-            mTmpClipRect.offset(0, -offsetTop);
-            mTmpClipRect.intersect(mClipRect);
-            mTmpClipRect.offset(0, offsetTop);
+            // Don't apply the workaround to apps explicitly requesting fullscreen layout.
+            if ((w.mSystemUiVisibility & SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN)
+                    == SYSTEM_UI_FLAGS_LAYOUT_STABLE_FULLSCREEN) {
+                mTmpClipRect.intersect(mClipRect);
+            } else {
+                mTmpClipRect.offset(0, -offsetTop);
+                mTmpClipRect.intersect(mClipRect);
+                mTmpClipRect.offset(0, offsetTop);
+            }
             clipRect = mTmpClipRect;
 
         }
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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 22e2a6e..9b3f7ac 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -124,8 +124,8 @@
             "com.android.server.usb.UsbService$Lifecycle";
     private static final String WIFI_SERVICE_CLASS =
             "com.android.server.wifi.WifiService";
-    private static final String WIFI_HOTSPOT_SERVICE_CLASS =
-            "com.android.server.wifi.hotspot.WifiHotspotService";
+    private static final String WIFI_PASSPOINT_SERVICE_CLASS =
+            "com.android.server.wifi.passpoint.WifiPasspointService";
     private static final String WIFI_P2P_SERVICE_CLASS =
             "com.android.server.wifi.p2p.WifiP2pService";
     private static final String HDMI_CEC_SERVICE_CLASS =
@@ -639,9 +639,9 @@
                 }
 
                 try {
-                    mSystemServiceManager.startService(WIFI_HOTSPOT_SERVICE_CLASS);
+                    mSystemServiceManager.startService(WIFI_PASSPOINT_SERVICE_CLASS);
                 } catch (Throwable e) {
-                    reportWtf("starting Wi-Fi HotspotService", e);
+                    reportWtf("starting Wi-Fi PasspointService", e);
                 }
 
                 try {
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/telecomm/java/android/telecomm/Connection.java b/telecomm/java/android/telecomm/Connection.java
new file mode 100644
index 0000000..6b7463c
--- /dev/null
+++ b/telecomm/java/android/telecomm/Connection.java
@@ -0,0 +1,412 @@
+/*
+ * 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.telecomm;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Represents a connection to a remote endpoint that carries voice traffic.
+ */
+public abstract class Connection {
+
+    private static String TAG = Connection.class.getSimpleName();
+
+    public interface Listener {
+        void onStateChanged(Connection c, int state);
+        void onAudioStateChanged(Connection c, CallAudioState state);
+        void onHandleChanged(Connection c, Uri newHandle);
+        void onSignalChanged(Connection c, Bundle details);
+        void onDisconnected(Connection c, int cause, String message);
+        void onDestroyed(Connection c);
+    }
+
+    public static class ListenerBase implements Listener {
+        /** {@inheritDoc} */
+        @Override
+        public void onStateChanged(Connection c, int state) {}
+
+        /** {@inheritDoc} */
+         @Override
+        public void onAudioStateChanged(Connection c, CallAudioState state) {}
+
+        /** {@inheritDoc} */
+        @Override
+        public void onHandleChanged(Connection c, Uri newHandle) {}
+
+        /** {@inheritDoc} */
+        @Override
+        public void onSignalChanged(Connection c, Bundle details) {}
+
+        /** {@inheritDoc} */
+        @Override
+        public void onDisconnected(Connection c, int cause, String message) {}
+
+        /** {@inheritDoc} */
+        @Override
+        public void onDestroyed(Connection c) {}
+    }
+
+    public final class State {
+        private State() {}
+
+        public static final int NEW = 0;
+        public static final int RINGING = 1;
+        public static final int DIALING = 2;
+        public static final int ACTIVE = 3;
+        public static final int HOLDING = 4;
+        public static final int DISCONNECTED = 5;
+    }
+
+    private final Set<Listener> mListeners = new HashSet<>();
+    private int mState = State.NEW;
+    private CallAudioState mCallAudioState;
+    private Uri mHandle;
+
+    /**
+     * Create a new Connection.
+     */
+    protected Connection() {}
+
+    /**
+     * @return The handle (e.g., phone number) to which this Connection
+     *         is currently communicating.
+     */
+    public final Uri getHandle() {
+        return mHandle;
+    }
+
+    /**
+     * @return The state of this Connection.
+     *
+     * @hide
+     */
+    public final int getState() {
+        return mState;
+    }
+
+    /**
+     * @return The audio state of the call, describing how its audio is currently
+     *         being routed by the system. This is {@code null} if this Connection
+     *         does not directly know about its audio state.
+     */
+    public final CallAudioState getCallAudioState() {
+        return mCallAudioState;
+    }
+
+    /**
+     * Assign a listener to be notified of state changes.
+     *
+     * @param l A listener.
+     * @return This Connection.
+     *
+     * @hide
+     */
+    public final Connection addConnectionListener(Listener l) {
+        mListeners.add(l);
+        return this;
+    }
+
+    /**
+     * Remove a previously assigned listener that was being notified of state changes.
+     *
+     * @param l A Listener.
+     * @return This Connection.
+     *
+     * @hide
+     */
+    public final Connection removeConnectionListener(Listener l) {
+        mListeners.remove(l);
+        return this;
+    }
+
+    /**
+     * Play a DTMF tone in this Connection.
+     *
+     * @param c A DTMF character.
+     *
+     * @hide
+     */
+    public final void playDtmfTone(char c) {
+        Log.d(TAG, "playDtmfTone " + c);
+        onPlayDtmfTone(c);
+    }
+
+    /**
+     * Stop any DTMF tones which may be playing in this Connection.
+     *
+     * @hide
+     */
+    public final void stopDtmfTone() {
+        Log.d(TAG, "stopDtmfTone");
+        onStopDtmfTone();
+    }
+
+    /**
+     * Disconnect this Connection. If and when the Connection can comply with
+     * this request, it will transition to the {@link State#DISCONNECTED}
+     * state and notify its listeners.
+     *
+     * @hide
+     */
+    public final void disconnect() {
+        Log.d(TAG, "disconnect");
+        onDisconnect();
+    }
+
+    /**
+     * Abort this Connection. The Connection will immediately transition to
+     * the {@link State#DISCONNECTED} state, and send no notifications of this
+     * or any other future events.
+     *
+     * @hide
+     */
+    public final void abort() {
+        Log.d(TAG, "abort");
+        onAbort();
+    }
+
+    /**
+     * Place this Connection on hold. If and when the Connection can comply with
+     * this request, it will transition to the {@link State#HOLDING}
+     * state and notify its listeners.
+     *
+     * @hide
+     */
+    public final void hold() {
+        Log.d(TAG, "hold");
+        onHold();
+    }
+
+    /**
+     * Un-hold this Connection. If and when the Connection can comply with
+     * this request, it will transition to the {@link State#ACTIVE}
+     * state and notify its listeners.
+     *
+     * @hide
+     */
+    public final void unhold() {
+        Log.d(TAG, "unhold");
+        onUnhold();
+    }
+
+    /**
+     * Accept a {@link State#RINGING} Connection. If and when the Connection
+     * can comply with this request, it will transition to the {@link State#ACTIVE}
+     * state and notify its listeners.
+     *
+     * @hide
+     */
+    public final void answer() {
+        Log.d(TAG, "answer");
+        if (mState == State.RINGING) {
+            onAnswer();
+        }
+    }
+
+    /**
+     * Reject a {@link State#RINGING} Connection. If and when the Connection
+     * can comply with this request, it will transition to the {@link State#ACTIVE}
+     * state and notify its listeners.
+     *
+     * @hide
+     */
+    public final void reject() {
+        Log.d(TAG, "reject");
+        if (mState == State.RINGING) {
+            onReject();
+        }
+    }
+
+    /**
+     * Inform this Connection that the state of its audio output has been changed externally.
+     *
+     * @param state The new audio state.
+     */
+    public void setAudioState(CallAudioState state) {
+        Log.d(TAG, "setAudioState " + state);
+        onSetAudioState(state);
+    }
+
+    /**
+     * @param state An integer value from {@link State}.
+     * @return A string representation of the value.
+     */
+    public static String stateToString(int state) {
+        switch (state) {
+            case State.NEW:
+                return "NEW";
+            case State.RINGING:
+                return "RINGING";
+            case State.DIALING:
+                return "DIALING";
+            case State.ACTIVE:
+                return "ACTIVE";
+            case State.HOLDING:
+                return "HOLDING";
+            case State.DISCONNECTED:
+                return "DISCONNECTED";
+            default:
+                Log.wtf(TAG, "Unknown state " + state);
+                return "UNKNOWN";
+        }
+    }
+
+    /**
+     * Sets the value of the {@link #getHandle()} property and notifies listeners.
+     *
+     * @param handle The new handle.
+     */
+    protected void setHandle(Uri handle) {
+        Log.d(TAG, "setHandle " + handle);
+        // TODO: Enforce super called
+        mHandle = handle;
+        for (Listener l : mListeners) {
+            l.onHandleChanged(this, handle);
+        }
+    }
+
+    /**
+     * Sets state to active (e.g., an ongoing call where two or more parties can actively
+     * communicate).
+     */
+    protected void setActive() {
+        setState(State.ACTIVE);
+    }
+
+    /**
+     * Sets state to ringing (e.g., an inbound ringing call).
+     */
+    protected void setRinging() {
+        setState(State.RINGING);
+    }
+
+    /**
+     * Sets state to dialing (e.g., dialing an outbound call).
+     */
+    protected void setDialing() {
+        setState(State.DIALING);
+    }
+
+    /**
+     * Sets state to be on hold.
+     */
+    protected void setOnHold() {
+        setState(State.HOLDING);
+    }
+
+    /**
+     * Sets state to disconnected. This will first notify listeners with an
+     * {@link Listener#onStateChanged(Connection, int)} event, then will fire an
+     * {@link Listener#onDisconnected(Connection, int, String)} event with additional
+     * details.
+     *
+     * @param cause The reason for the disconnection, any of
+     *         {@link android.telephony.DisconnectCause}.
+     * @param message Optional call-service-provided message about the disconnect.
+     */
+    protected void setDisconnected(int cause, String message) {
+        setState(State.DISCONNECTED);
+        Log.d(TAG, "Disconnected with cause " + cause + " message " + message);
+        for (Listener l : mListeners) {
+            l.onDisconnected(this, cause, message);
+        }
+    }
+
+    /**
+     * Notifies this Connection and listeners that the {@link #getCallAudioState()} property
+     * has a new value.
+     *
+     * @param state The new call audio state.
+     */
+    protected void onSetAudioState(CallAudioState state) {
+        // TODO: Enforce super called
+        this.mCallAudioState = state;
+        for (Listener l : mListeners) {
+            l.onAudioStateChanged(this, state);
+        }
+    }
+
+    /**
+     * Notifies this Connection and listeners of a change in the current signal levels
+     * for the underlying data transport.
+     *
+     * @param details A {@link android.os.Bundle} containing details of the current level.
+     */
+    protected void onSetSignal(Bundle details) {
+        // TODO: Enforce super called
+        for (Listener l : mListeners) {
+            l.onSignalChanged(this, details);
+        }
+    }
+
+    /**
+     * Notifies this Connection of a request to play a DTMF tone.
+     *
+     * @param c A DTMF character.
+     */
+    protected void onPlayDtmfTone(char c) {}
+
+    /**
+     * Notifies this Connection of a request to stop any currently playing DTMF tones.
+     */
+    protected void onStopDtmfTone() {}
+
+    /**
+     * Notifies this Connection of a request to disconnect.
+     */
+    protected void onDisconnect() {}
+
+    /**
+     * Notifies this Connection of a request to abort.
+     */
+    protected void onAbort() {}
+
+    /**
+     * Notifies this Connection of a request to hold.
+     */
+    protected void onHold() {}
+
+    /**
+     * Notifies this Connection of a request to exit a hold state.
+     */
+    protected void onUnhold() {}
+
+    /**
+     * Notifies this Connection, which is in {@link State#RINGING}, of
+     * a request to accept.
+     */
+    protected void onAnswer() {}
+
+    /**
+     * Notifies this Connection, which is in {@link State#RINGING}, of
+     * a request to reject.
+     */
+    protected void onReject() {}
+
+    private void setState(int state) {
+        Log.d(TAG, "setState: " + stateToString(state));
+        this.mState = state;
+        for (Listener l : mListeners) {
+            l.onStateChanged(this, state);
+        }
+    }
+}
diff --git a/telecomm/java/android/telecomm/ConnectionRequest.java b/telecomm/java/android/telecomm/ConnectionRequest.java
new file mode 100644
index 0000000..c1f1871
--- /dev/null
+++ b/telecomm/java/android/telecomm/ConnectionRequest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.telecomm;
+
+import android.os.Bundle;
+import android.net.Uri;
+
+/**
+ * Simple data container encapsulating a request to some entity to
+ * create a new {@link Connection}.
+ */
+public final class ConnectionRequest {
+
+    // TODO: Token to limit recursive invocations
+    // TODO: Consider upgrading "mHandle" to ordered list of handles, indicating a set of phone
+    //         numbers that would satisfy the client's needs, in order of preference
+    private final Uri mHandle;
+    private final Bundle mExtras;
+
+    public ConnectionRequest(Uri handle, Bundle extras) {
+        mHandle = handle; mExtras = extras;
+    }
+
+    /**
+     * The handle (e.g., phone number) to which the {@link Connection} is to connect.
+     */
+    public Uri getHandle() { return mHandle; }
+
+    /**
+     * Application-specific extra data. Used for passing back information from an incoming
+     * call {@code Intent}, and for any proprietary extensions arranged between a client
+     * and servant {@code ConnectionService} which agree on a vocabulary for such data.
+     */
+    public Bundle getExtras() { return mExtras; }
+
+    public String toString() {
+        return String.format("PhoneConnectionRequest %s %s",
+                mHandle == null
+                        ? Uri.EMPTY
+                        : ConnectionService.toLogSafePhoneNumber(mHandle.toString()),
+                mExtras == null ? "" : mExtras);
+    }
+}
diff --git a/telecomm/java/android/telecomm/ConnectionService.java b/telecomm/java/android/telecomm/ConnectionService.java
new file mode 100644
index 0000000..aba4579
--- /dev/null
+++ b/telecomm/java/android/telecomm/ConnectionService.java
@@ -0,0 +1,345 @@
+/*
+ * 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.telecomm;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A {@link android.app.Service} that provides telephone connections to
+ * processes running on an Android device.
+ */
+public abstract class ConnectionService extends CallService {
+    private static final String TAG = ConnectionService.class.getSimpleName();
+
+    // STOPSHIP: Debug Logging should be conditional on a debug flag or use a set of
+    // logging functions that make it automaticaly so.
+
+    // Flag controlling whether PII is emitted into the logs
+    private static final boolean PII_DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private static final Connection NULL_CONNECTION = new Connection() {};
+
+    // Mappings from Connections to IDs as understood by the current CallService implementation
+    private final Map<String, Connection> mConnectionById = new HashMap<>();
+    private final Map<Connection, String> mIdByConnection = new HashMap<>();
+
+    private final Connection.Listener mConnectionListener = new Connection.Listener() {
+        @Override
+        public void onStateChanged(Connection c, int state) {
+            String id = mIdByConnection.get(c);
+            Log.d(TAG, "Adapter set state " + id + " " + Connection.stateToString(state));
+            switch (state) {
+                case Connection.State.ACTIVE:
+                    getAdapter().setActive(id);
+                    break;
+                case Connection.State.DIALING:
+                    getAdapter().setDialing(id);
+                    break;
+                case Connection.State.DISCONNECTED:
+                    // Handled in onDisconnected()
+                    break;
+                case Connection.State.HOLDING:
+                    getAdapter().setOnHold(id);
+                    break;
+                case Connection.State.NEW:
+                    // Nothing to tell Telecomm
+                    break;
+                case Connection.State.RINGING:
+                    getAdapter().setRinging(id);
+                    break;
+            }
+        }
+
+        @Override
+        public void onDisconnected(Connection c, int cause, String message) {
+            String id = mIdByConnection.get(c);
+            Log.d(TAG, "Adapter set disconnected " + cause + " " + message);
+            getAdapter().setDisconnected(id, cause, message);
+        }
+
+        @Override
+        public void onHandleChanged(Connection c, Uri newHandle) {
+            // TODO: Unsupported yet
+        }
+
+        @Override
+        public void onAudioStateChanged(Connection c, CallAudioState state) {
+            // TODO: Unsupported yet
+        }
+
+        @Override
+        public void onSignalChanged(Connection c, Bundle details) {
+            // TODO: Unsupported yet
+        }
+
+        @Override
+        public void onDestroyed(Connection c) {
+            removeConnection(c);
+        }
+    };
+
+    @Override
+    public final void isCompatibleWith(final CallInfo callInfo) {
+        Log.d(TAG, "isCompatibleWith " + callInfo);
+        onFindSubscriptions(
+                callInfo.getHandle(),
+                new Response<Uri, Subscription>() {
+                    @Override
+                    public void onResult(Uri handle, Subscription... result) {
+                        boolean isCompatible = result.length > 0;
+                        Log.d(TAG, "adapter setIsCompatibleWith "
+                                + callInfo.getId() + " " + isCompatible);
+                        getAdapter().setIsCompatibleWith(callInfo.getId(), isCompatible);
+                    }
+
+                    @Override
+                    public void onError(Uri handle, String reason) {
+                        Log.wtf(TAG, "Error in onFindSubscriptions " + callInfo.getHandle()
+                                + " error: " + reason);
+                        getAdapter().setIsCompatibleWith(callInfo.getId(), false);
+                    }
+                }
+        );
+    }
+
+    @Override
+    public final void call(final CallInfo callInfo) {
+        Log.d(TAG, "call " + callInfo);
+        onCreateConnections(
+                new ConnectionRequest(
+                        callInfo.getHandle(),
+                        callInfo.getExtras()),
+                new Response<ConnectionRequest, Connection>() {
+                    @Override
+                    public void onResult(ConnectionRequest request, Connection... result) {
+                        if (result.length != 1) {
+                            Log.d(TAG, "adapter handleFailedOutgoingCall " + callInfo);
+                            getAdapter().handleFailedOutgoingCall(
+                                    callInfo.getId(),
+                                    "Created " + result.length + " Connections, expected 1");
+                            for (Connection c : result) {
+                                c.abort();
+                            }
+                        } else {
+                            addConnection(callInfo.getId(), result[0]);
+                            Log.d(TAG, "adapter handleSuccessfulOutgoingCall "
+                                    + callInfo.getId());
+                            getAdapter().handleSuccessfulOutgoingCall(callInfo.getId());
+                        }
+                    }
+
+                    @Override
+                    public void onError(ConnectionRequest request, String reason) {
+                        getAdapter().handleFailedOutgoingCall(callInfo.getId(), reason);
+                    }
+                }
+        );
+    }
+
+    @Override
+    public final void abort(String callId) {
+        Log.d(TAG, "abort " + callId);
+        findConnectionForAction(callId, "abort").abort();
+    }
+
+    @Override
+    public final void setIncomingCallId(final String callId, Bundle extras) {
+        Log.d(TAG, "setIncomingCallId " + callId + " " + extras);
+        onCreateIncomingConnection(
+                new ConnectionRequest(
+                        null,  // TODO: Can we obtain this from "extras"?
+                        extras),
+                new Response<ConnectionRequest, Connection>() {
+                    @Override
+                    public void onResult(ConnectionRequest request, Connection... result) {
+                        if (result.length != 1) {
+                            Log.d(TAG, "adapter handleFailedOutgoingCall " + callId);
+                            getAdapter().handleFailedOutgoingCall(
+                                    callId,
+                                    "Created " + result.length + " Connections, expected 1");
+                            for (Connection c : result) {
+                                c.abort();
+                            }
+                        } else {
+                            addConnection(callId, result[0]);
+                            Log.d(TAG, "adapter notifyIncomingCall " + callId);
+                            // TODO: Uri.EMPTY is because CallInfo crashes when Parceled with a
+                            // null URI ... need to fix that at its cause!
+                            getAdapter().notifyIncomingCall(new CallInfo(
+                                    callId,
+                                    connectionStateToCallState(result[0].getState()),
+                                    request.getHandle() /* result[0].getHandle() == null
+                                            ? Uri.EMPTY : result[0].getHandle() */));
+                        }
+                    }
+
+                    @Override
+                    public void onError(ConnectionRequest request, String reason) {
+                        Log.d(TAG, "adapter failed setIncomingCallId " + request + " " + reason);
+                    }
+                }
+        );
+    }
+
+    @Override
+    public final void answer(String callId) {
+        Log.d(TAG, "answer " + callId);
+        findConnectionForAction(callId, "answer").answer();
+    }
+
+    @Override
+    public final void reject(String callId) {
+        Log.d(TAG, "reject " + callId);
+        findConnectionForAction(callId, "reject").reject();
+    }
+
+    @Override
+    public final void disconnect(String callId) {
+        Log.d(TAG, "disconnect " + callId);
+        findConnectionForAction(callId, "disconnect").disconnect();
+    }
+
+    @Override
+    public final void hold(String callId) {
+        Log.d(TAG, "hold " + callId);
+        findConnectionForAction(callId, "hold").hold();
+    }
+
+    @Override
+    public final void unhold(String callId) {
+        Log.d(TAG, "unhold " + callId);
+        findConnectionForAction(callId, "unhold").unhold();
+    }
+
+    @Override
+    public final void playDtmfTone(String callId, char digit) {
+        Log.d(TAG, "playDtmfTone " + callId + " " + Character.toString(digit));
+        findConnectionForAction(callId, "playDtmfTone").playDtmfTone(digit);
+    }
+
+    @Override
+    public final void stopDtmfTone(String callId) {
+        Log.d(TAG, "stopDtmfTone " + callId);
+        findConnectionForAction(callId, "stopDtmfTone").stopDtmfTone();
+    }
+
+    @Override
+    public final void onAudioStateChanged(String callId, CallAudioState audioState) {
+        Log.d(TAG, "onAudioStateChanged " + callId + " " + audioState);
+        findConnectionForAction(callId, "onAudioStateChanged").setAudioState(audioState);
+    }
+
+    /**
+     * Find a set of Subscriptions matching a given handle (e.g. phone number).
+     *
+     * @param handle A handle (e.g. phone number) with which to connect.
+     * @param callback A callback for providing the result.
+     */
+    public void onFindSubscriptions(
+            Uri handle,
+            Response<Uri, Subscription> callback) {}
+
+    /**
+     * Create a Connection given a request.
+     *
+     * @param request Data encapsulating details of the desired Connection.
+     * @param callback A callback for providing the result.
+     */
+    public void onCreateConnections(
+            ConnectionRequest request,
+            Response<ConnectionRequest, Connection> callback) {}
+
+    /**
+     * Create a Connection to match an incoming connection notification.
+     *
+     * @param request Data encapsulating details of the desired Connection.
+     * @param callback A callback for providing the result.
+     */
+    public void onCreateIncomingConnection(
+            ConnectionRequest request,
+            Response<ConnectionRequest, Connection> callback) {}
+
+    static String toLogSafePhoneNumber(String number) {
+        // For unknown number, log empty string.
+        if (number == null) {
+            return "";
+        }
+
+        if (PII_DEBUG) {
+            // When PII_DEBUG is true we emit PII.
+            return number;
+        }
+
+        // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare
+        // sanitized phone numbers.
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < number.length(); i++) {
+            char c = number.charAt(i);
+            if (c == '-' || c == '@' || c == '.') {
+                builder.append(c);
+            } else {
+                builder.append('x');
+            }
+        }
+        return builder.toString();
+    }
+
+    private CallState connectionStateToCallState(int connectionState) {
+        switch (connectionState) {
+            case Connection.State.NEW:
+                return CallState.NEW;
+            case Connection.State.RINGING:
+                return CallState.RINGING;
+            case Connection.State.DIALING:
+                return CallState.DIALING;
+            case Connection.State.ACTIVE:
+                return CallState.ACTIVE;
+            case Connection.State.HOLDING:
+                return CallState.ON_HOLD;
+            case Connection.State.DISCONNECTED:
+                return CallState.DISCONNECTED;
+            default:
+                Log.wtf(TAG, "Unknown Connection.State " + connectionState);
+                return CallState.NEW;
+        }
+    }
+
+    private void addConnection(String callId, Connection connection) {
+        mConnectionById.put(callId, connection);
+        mIdByConnection.put(connection, callId);
+        connection.addConnectionListener(mConnectionListener);
+    }
+
+    private void removeConnection(Connection connection) {
+        connection.removeConnectionListener(mConnectionListener);
+        mConnectionById.remove(mIdByConnection.get(connection));
+        mIdByConnection.remove(connection);
+    }
+
+    private Connection findConnectionForAction(String callId, String action) {
+        if (mConnectionById.containsKey(callId)) {
+            return mConnectionById.get(callId);
+        }
+        Log.wtf(TAG, action + " - Cannot find Connection \"" + callId + "\"");
+        return NULL_CONNECTION;
+    }
+}
\ No newline at end of file
diff --git a/telecomm/java/android/telecomm/Response.java b/telecomm/java/android/telecomm/Response.java
new file mode 100644
index 0000000..14f8340
--- /dev/null
+++ b/telecomm/java/android/telecomm/Response.java
@@ -0,0 +1,39 @@
+/*
+ * 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.telecomm;
+
+/**
+ * Used to inform a client of asynchronously returned results.
+ */
+public interface Response<IN, OUT> {
+
+    /**
+     * Provide a set of results.
+     *
+     * @param request The original request.
+     * @param result The results.
+     */
+    void onResult(IN request, OUT... result);
+
+    /**
+     * Indicates the inability to provide results.
+     *
+     * @param request The original request.
+     * @param reason The reason for the failure.
+     */
+    void onError(IN request, String reason);
+}
diff --git a/telecomm/java/android/telecomm/Subscription.java b/telecomm/java/android/telecomm/Subscription.java
new file mode 100644
index 0000000..f187f4d
--- /dev/null
+++ b/telecomm/java/android/telecomm/Subscription.java
@@ -0,0 +1,48 @@
+/*
+ * 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.telecomm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a distinct subscription, line of service or call placement method that
+ * a {@link ConnectionService} can use to place phone calls.
+ */
+public class Subscription implements Parcelable {
+
+    public Subscription() {}
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {}
+
+    public static final Parcelable.Creator<Subscription> CREATOR
+            = new Parcelable.Creator<Subscription>() {
+        public Subscription createFromParcel(Parcel in) {
+            return new Subscription(in);
+        }
+
+        public Subscription[] newArray(int size) {
+            return new Subscription[size];
+        }
+    };
+
+    private Subscription(Parcel in) {}
+}
diff --git a/telephony/java/android/telephony/CallStateListener.java b/telephony/java/android/telephony/CallStateListener.java
deleted file mode 100644
index e2ffbfa..0000000
--- a/telephony/java/android/telephony/CallStateListener.java
+++ /dev/null
@@ -1,36 +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 android.telephony;
-
-import android.annotation.PrivateApi;
-
-/** @hide */
-@PrivateApi
-public interface CallStateListener {
-    /**
-     * Notify of a new or updated call.
-     * Any time the state of a call is updated, it will alert any listeners. This includes changes
-     * of state such as when a call is put on hold or conferenced.
-     *
-     * @param callId a unique ideCntifier for a given call that can be used to track state changes
-     * @param state the new state of the call.
-     *              {@see com.android.services.telephony.common.Call$State}
-     * @param number the phone number of the call. For some states, this may be blank. However, it
-     *               will be populated for any initial state.
-     */
-    public void onCallStateChanged(int callId, int state, String number);
-}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7002744..cb3ffb9 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -82,40 +82,8 @@
         static final int NEVER_USE = 2;
     }
 
-    private final HashMap<CallStateListener,Listener> mListeners
-            = new HashMap<CallStateListener,Listener>();
     private final Context mContext;
 
-    private static class Listener extends ITelephonyListener.Stub {
-        final CallStateListener mListener;
-        private static final int WHAT = 1;
-
-        private Handler mHandler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                mListener.onCallStateChanged(msg.arg1, msg.arg2, (String)msg.obj);
-            }
-        };
-
-        Listener(CallStateListener listener) {
-            mListener = listener;
-        }
-
-        @Override
-        public void onUpdate(final int callId, final int state, final String number) {
-            if (mHandler != null) {
-                mHandler.sendMessage(mHandler.obtainMessage(WHAT, callId, state, number));
-            }
-        }
-
-        void clearQueue() {
-            mHandler.removeMessages(WHAT);
-
-            // Don't accept more incoming binder calls either.
-            mHandler = null;
-        }
-    }
-
     /** @hide */
     public TelephonyManager(Context context) {
         Context appContext = context.getApplicationContext();
@@ -1773,12 +1741,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 +1761,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 +1782,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 +1800,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) {
         }
@@ -2016,46 +2015,6 @@
 
     /** @hide */
     @PrivateApi
-    public void toggleHold() {
-        try {
-            getITelephony().toggleHold();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#toggleHold", e);
-        }
-    }
-
-    /** @hide */
-    @PrivateApi
-    public void merge() {
-        try {
-            getITelephony().merge();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#merge", e);
-        }
-    }
-
-    /** @hide */
-    @PrivateApi
-    public void swap() {
-        try {
-            getITelephony().swap();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#swap", e);
-        }
-    }
-
-    /** @hide */
-    @PrivateApi
-    public void mute(boolean mute) {
-        try {
-            getITelephony().mute(mute);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#mute", e);
-        }
-    }
-
-    /** @hide */
-    @PrivateApi
     public void silenceRinger() {
         try {
             getITelephony().silenceRinger();
@@ -2291,56 +2250,4 @@
         }
         return false;
     }
-
-    /** @hide */
-    @PrivateApi
-    public void playDtmfTone(char digit, boolean timedShortCode) {
-        try {
-            getITelephony().playDtmfTone(digit, timedShortCode);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#playDtmfTone", e);
-        }
-    }
-
-    /** @hide */
-    @PrivateApi
-    public void stopDtmfTone() {
-        try {
-            getITelephony().stopDtmfTone();
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#stopDtmfTone", e);
-        }
-    }
-
-    /** @hide */
-    @PrivateApi
-    public void addCallStateListener(CallStateListener listener) {
-        try {
-            if (listener == null) {
-                throw new RuntimeException("Listener can't be null");
-            }
-            if (!mListeners.containsKey(listener)) {
-                final Listener l = new Listener(listener);
-                mListeners.put(listener, l);
-                getITelephony().addListener(l);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#addListener", e);
-        }
-    }
-
-    /** @hide */
-    @PrivateApi
-    public void removeCallStateListener(CallStateListener listener) {
-        try {
-            final Listener l = mListeners.remove(listener);
-            if (l != null) {
-                // Make sure that no callbacks that are already in flight come.
-                l.clearQueue();
-                getITelephony().removeListener(l);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#removeListener", e);
-        }
-    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 72398ad..baacb74 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -21,8 +21,6 @@
 import android.telephony.CellInfo;
 import android.telephony.NeighboringCellInfo;
 
-import com.android.internal.telephony.ITelephonyListener;
-
 import java.util.List;
 
 import java.util.List;
@@ -373,6 +371,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.
      *
@@ -426,47 +436,4 @@
      * @return true on success; false on any failure.
      */
     boolean setPreferredNetworkType(int networkType);
-
-    /**
-     * Put a call on hold.
-     */
-     void toggleHold();
-
-     /**
-      * Merge foreground and background calls.
-      */
-     void merge();
-
-     /**
-      * Swap foreground and background calls.
-      */
-     void swap();
-
-     /**
-      * Mute the phone.
-      */
-     void mute(boolean mute);
-
-    /**
-     * Start playing DTMF tone for the specified digit.
-     *
-     * @param digit the digit that corresponds with the desired tone.
-     * @param timedShortcode whether the specified digit should be played as a timed short code.
-     */
-     void playDtmfTone(char digit, boolean timedShortCode);
-
-     /**
-      * Stop playing DTMF tones.
-      */
-     void stopDtmfTone();
-
-     /**
-       * Register a callback.
-       */
-      void addListener(ITelephonyListener listener);
-
-      /**
-       * Unregister a callback.
-       */
-      void removeListener(ITelephonyListener listener);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyListener.aidl b/telephony/java/com/android/internal/telephony/ITelephonyListener.aidl
deleted file mode 100644
index c226217..0000000
--- a/telephony/java/com/android/internal/telephony/ITelephonyListener.aidl
+++ /dev/null
@@ -1,27 +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.internal.telephony;
-
-/**
- * Interface used to register a listener that gets more detailed call state information than
- * {@link android.telephony.PhoneStateListener}
- *
- * {@hide}
- */
-oneway interface ITelephonyListener {
-    void onUpdate(int callId, int state, String number);
-}
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 0d9cd18..c162bf2 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..5b0aa66 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/CirclePropActivity.java
@@ -109,27 +109,29 @@
             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.start(this);
+                anim.setDuration(1000);
+                anim.setTarget(this);
+                anim.start();
             }
 
             if (mToggle) {
@@ -145,7 +147,6 @@
                     }
                 });
             }
-
             return true;
         }
     }
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..af448e8
--- /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..c7715ad 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,21 @@
             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);
-            animator.start(child);
+            if (child == clickedView) logTranslationY(clickedView);
+            animator.setTarget(child);
+            animator.start();
+            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/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0535fe0..9ccd810 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -111,8 +111,6 @@
 
     Messenger getWifiServiceMessenger();
 
-    Messenger getWifiStateMachineMessenger();
-
     String getConfigFile();
 
     void enableTdls(String remoteIPAddress, boolean enable);
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 1cb9546..3e3b6e3 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -16,6 +16,8 @@
 
 package android.net.wifi;
 
+import android.net.wifi.passpoint.PasspointInfo;
+import android.net.wifi.passpoint.PasspointManager;
 import android.os.Parcelable;
 import android.os.Parcel;
 
@@ -77,6 +79,13 @@
     public int distanceSdCm;
 
     /**
+     * Passpoint ANQP information. This is not fetched automatically.
+     * Use {@link PasspointManager#requestAnqpInfo} to request ANQP info.
+     * {@hide}
+     */
+    public PasspointInfo passpoint;
+
+    /**
      * {@hide}
      */
     public final static int UNSPECIFIED = -1;
@@ -122,6 +131,8 @@
             distanceCm = source.distanceCm;
             distanceSdCm = source.distanceSdCm;
             seen = source.seen;
+            if (source.passpoint != null)
+                passpoint = new PasspointInfo(source.passpoint);
         }
     }
 
@@ -155,6 +166,9 @@
         sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
                 append("(cm)");
 
+        if (passpoint != null)
+            sb.append(", passpoint: [").append(passpoint.toString()).append("]");
+
         return sb.toString();
     }
 
@@ -178,6 +192,12 @@
         dest.writeLong(timestamp);
         dest.writeInt(distanceCm);
         dest.writeInt(distanceSdCm);
+        if (passpoint != null) {
+            dest.writeInt(1);
+            passpoint.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -188,7 +208,7 @@
                 if (in.readInt() == 1) {
                     wifiSsid = WifiSsid.CREATOR.createFromParcel(in);
                 }
-                return new ScanResult(
+                ScanResult sr = new ScanResult(
                     wifiSsid,
                     in.readString(),
                     in.readString(),
@@ -198,6 +218,10 @@
                     in.readInt(),
                     in.readInt()
                 );
+                if (in.readInt() == 1) {
+                    sr.passpoint = PasspointInfo.CREATOR.createFromParcel(in);
+                }
+                return sr;
             }
 
             public ScanResult[] newArray(int size) {
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 85b81d9..e73cce1 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;
             }
 
diff --git a/wifi/java/android/net/wifi/WifiLinkLayerStats.java b/wifi/java/android/net/wifi/WifiLinkLayerStats.java
new file mode 100644
index 0000000..922eddd
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiLinkLayerStats.java
@@ -0,0 +1,189 @@
+/*
+ * 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.net.wifi;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.text.TextUtils;
+import java.util.HashMap;
+import java.util.Date;
+import java.util.ArrayList;
+
+import java.util.BitSet;
+
+/**
+ * A class representing link layer statistics collected over a Wifi Interface.
+ */
+/** {@hide} */
+public class WifiLinkLayerStats implements Parcelable {
+    private static final String TAG = "WifiLinkLayerStats";
+
+    /**
+     * The current status of this network configuration entry.
+     * @see Status
+     */
+    /** {@hide} */
+    public int status;
+
+    /**
+     * The network's SSID. Can either be an ASCII string,
+     * which must be enclosed in double quotation marks
+     * (e.g., {@code "MyNetwork"}, or a string of
+     * hex digits,which are not enclosed in quotes
+     * (e.g., {@code 01a243f405}).
+     */
+    /** {@hide} */
+    public String SSID;
+    /**
+     * When set. this is the BSSID the radio is currently associated with.
+     * The value is a string in the format of an Ethernet MAC address, e.g.,
+     * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit.
+     */
+    /** {@hide} */
+    public String BSSID;
+
+    /* number beacons received from our own AP */
+    /** {@hide} */
+    public int beacon_rx;
+
+    /* RSSI taken on management frames */
+    /** {@hide} */
+    public int rssi_mgmt;
+
+    /* packets counters */
+    /** {@hide} */
+    /* WME Best Effort Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries)*/
+    public long rxmpdu_be;
+    /** {@hide} */
+    public long txmpdu_be;
+    /** {@hide} */
+    public long lostmpdu_be;
+    /** {@hide} */
+    public long retries_be;
+    /** {@hide} */
+    /* WME Background Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */
+    public long rxmpdu_bk;
+    /** {@hide} */
+    public long txmpdu_bk;
+    /** {@hide} */
+    public long lostmpdu_bk;
+    /** {@hide} */
+    public long retries_bk;
+    /** {@hide} */
+    /* WME Video Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */
+    public long rxmpdu_vi;
+    /** {@hide} */
+    public long txmpdu_vi;
+    /** {@hide} */
+    public long lostmpdu_vi;
+    /** {@hide} */
+    public long retries_vi;
+    /** {@hide} */
+    /* WME Voice Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */
+    public long rxmpdu_vo;
+    /** {@hide} */
+    public long txmpdu_vo;
+    /** {@hide} */
+    public long lostmpdu_vo;
+    /** {@hide} */
+    public long retries_vo;
+
+
+    /** {@hide} */
+    public WifiLinkLayerStats() {
+    }
+
+    @Override
+    /** {@hide} */
+    public String toString() {
+        StringBuilder sbuf = new StringBuilder();
+        if (this.SSID != null) {
+            sbuf.append(" SSID: ").append(this.SSID).append('\n');
+        }
+        if (this.BSSID != null) {
+            sbuf.append(" BSSID: ").append(this.BSSID).append('\n');
+        }
+
+        sbuf.append(" my bss beacon rx: ").append(Integer.toString(this.beacon_rx)).append('\n');
+        sbuf.append(" RSSI mgmt: ").append(Integer.toString(this.rssi_mgmt)).append('\n');
+        sbuf.append(" BE : ").append(" rx=").append(Long.toString(this.rxmpdu_be))
+                .append(" tx=").append(Long.toString(this.txmpdu_be))
+                .append(" lost=").append(Long.toString(this.lostmpdu_be))
+                .append(" retries=").append(Long.toString(this.retries_be)).append('\n');
+        sbuf.append(" BK : ").append(" rx=").append(Long.toString(this.rxmpdu_bk))
+                .append(" tx=").append(Long.toString(this.txmpdu_bk))
+                .append(" lost=").append(Long.toString(this.lostmpdu_bk))
+                .append(" retries=").append(Long.toString(this.retries_bk)).append('\n');
+        sbuf.append(" VI : ").append(" rx=").append(Long.toString(this.rxmpdu_vi))
+                .append(" tx=").append(Long.toString(this.txmpdu_vi))
+                .append(" lost=").append(Long.toString(this.lostmpdu_vi))
+                .append(" retries=").append(Long.toString(this.retries_vi)).append('\n');
+        sbuf.append(" VO : ").append(" rx=").append(Long.toString(this.rxmpdu_vo))
+                .append(" tx=").append(Long.toString(this.txmpdu_vo))
+                .append(" lost=").append(Long.toString(this.lostmpdu_vo))
+                .append(" retries=").append(Long.toString(this.retries_vo)).append('\n');
+
+        return sbuf.toString();
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public int describeContents() {
+        return 0;
+    }
+
+    /** {@hide} */
+    public String getPrintableSsid() {
+        if (SSID == null) return "";
+        final int length = SSID.length();
+        if (length > 2 && (SSID.charAt(0) == '"') && SSID.charAt(length - 1) == '"') {
+            return SSID.substring(1, length - 1);
+        }
+
+        /** The ascii-encoded string format is P"<ascii-encoded-string>"
+         * The decoding is implemented in the supplicant for a newly configured
+         * network.
+         */
+        if (length > 3 && (SSID.charAt(0) == 'P') && (SSID.charAt(1) == '"') &&
+                (SSID.charAt(length-1) == '"')) {
+            WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(
+                    SSID.substring(2, length - 1));
+            return wifiSsid.toString();
+        }
+        return SSID;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(SSID);
+        dest.writeString(BSSID);
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public static final Creator<WifiLinkLayerStats> CREATOR =
+        new Creator<WifiLinkLayerStats>() {
+            public WifiLinkLayerStats createFromParcel(Parcel in) {
+                WifiLinkLayerStats stats = new WifiLinkLayerStats();
+                stats.SSID = in.readString();
+                stats.BSSID = in.readString();
+                return stats;
+            };
+            public WifiLinkLayerStats[] newArray(int size) {
+                return new WifiLinkLayerStats[size];
+            }
+
+        };
+}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 15b65c1..9558d50 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1783,18 +1783,6 @@
         }
     }
 
-    /**
-     * Get a reference to WifiStateMachine handler.
-     * @return Messenger pointing to the WifiService handler
-     * @hide
-     */
-    public Messenger getWifiStateMachineMessenger() {
-        try {
-            return mService.getWifiStateMachineMessenger();
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
 
     /**
      * Returns the file in which IP and proxy configuration data is stored
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index e02e14c..b766268 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -31,7 +31,6 @@
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 
@@ -41,27 +40,45 @@
  * Get an instance of this class by calling
  * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context
  * .WIFI_SCANNING_SERVICE)}.
- * @hide
  */
 public class WifiScanner {
 
+    /** no band specified; use channel list instead */
     public static final int WIFI_BAND_UNSPECIFIED = 0;      /* not specified */
+
+    /** 2.4 GHz band */
     public static final int WIFI_BAND_24_GHZ = 1;           /* 2.4 GHz band */
+    /** 5 GHz band excluding DFS channels */
     public static final int WIFI_BAND_5_GHZ = 2;            /* 5 GHz band without DFS channels */
+    /** DFS channels from 5 GHz band only */
     public static final int WIFI_BAND_5_GHZ_DFS_ONLY  = 4;  /* 5 GHz band with DFS channels */
+    /** 5 GHz band including DFS channels */
     public static final int WIFI_BAND_5_GHZ_WITH_DFS  = 6;  /* 5 GHz band with DFS channels */
+    /** Both 2.4 GHz band and 5 GHz band; no DFS channels */
     public static final int WIFI_BAND_BOTH = 3;             /* both bands without DFS channels */
+    /** Both 2.4 GHz band and 5 GHz band; with DFS channels */
     public static final int WIFI_BAND_BOTH_WITH_DFS = 7;    /* both bands with DFS channels */
 
-    public static final int MIN_SCAN_PERIOD_MS = 300;       /* minimum supported period */
+    /** Minimum supported scanning period */
+    public static final int MIN_SCAN_PERIOD_MS = 2000;      /* minimum supported period */
+    /** Maximum supported scanning period */
     public static final int MAX_SCAN_PERIOD_MS = 1024000;   /* maximum supported period */
 
+    /** No Error */
     public static final int REASON_SUCCEEDED = 0;
+    /** Unknown error */
     public static final int REASON_UNSPECIFIED = -1;
+    /** Invalid listener */
     public static final int REASON_INVALID_LISTENER = -2;
+    /** Invalid request */
     public static final int REASON_INVALID_REQUEST = -3;
+    /** Request conflicts with other scans that may be going on */
     public static final int REASON_CONFLICTING_REQUEST = -4;
 
+    /**
+     * Generic action callback invocation interface
+     *  @hide
+     */
     public static interface ActionListener {
         public void onSuccess(Object result);
         public void onFailure(int reason, Object exception);
@@ -70,19 +87,35 @@
     /**
      * gives you all the possible channels; channel is specified as an
      * integer with frequency in MHz i.e. channel 1 is 2412
+     * @hide
      */
     public List<Integer> getAvailableChannels(int band) {
         return null;
     }
 
     /**
-     * provides channel specification to the APIs
+     * provides channel specification for scanning
      */
     public static class ChannelSpec {
+        /**
+         * channel frequency in KHz; for example channel 1 is specified as 2412
+         */
         public int frequency;
+        /**
+         * if true, scan this channel in passive fashion.
+         * This flag is ignored on DFS channel specification.
+         * @hide
+         */
         public boolean passive;                                    /* ignored on DFS channels */
+        /**
+         * how long to dwell on this channel
+         * @hide
+         */
         public int dwellTimeMS;                                    /* not supported for now */
 
+        /**
+         * default constructor for channel spec
+         */
         public ChannelSpec(int frequency) {
             this.frequency = frequency;
             passive = false;
@@ -90,19 +123,26 @@
         }
     }
 
+    /** reports {@link ScanListener#onResults} when underlying buffers are full */
     public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0;
+    /** reports {@link ScanListener#onResults} after each scan */
     public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1;
+    /** reports {@link ScanListener#onFullResult} whenever each beacon is discovered */
     public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2;
 
     /**
-     * scan configuration parameters
+     * scan configuration parameters to be sent to {@link #startBackgroundScan}
      */
     public static class ScanSettings implements Parcelable {
 
-        public int band;                                           /* ignore channels if specified */
-        public ChannelSpec[] channels;                             /* list of channels to scan */
-        public int periodInMs;                                     /* period of scan */
-        public int reportEvents;                                   /* a valid REPORT_EVENT value */
+        /** one of the WIFI_BAND values */
+        public int band;
+        /** list of channels; used when band is set to WIFI_BAND_UNSPECIFIED */
+        public ChannelSpec[] channels;
+        /** period of background scan; in millisecond */
+        public int periodInMs;
+        /** must have a valid REPORT_EVENT value */
+        public int reportEvents;
 
         /** Implement the Parcelable interface {@hide} */
         public int describeContents() {
@@ -113,6 +153,7 @@
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(band);
             dest.writeInt(periodInMs);
+            dest.writeInt(reportEvents);
             dest.writeInt(channels.length);
 
             for (int i = 0; i < channels.length; i++) {
@@ -130,6 +171,7 @@
                         ScanSettings settings = new ScanSettings();
                         settings.band = in.readInt();
                         settings.periodInMs = in.readInt();
+                        settings.reportEvents = in.readInt();
                         int num_channels = in.readInt();
                         settings.channels = new ChannelSpec[num_channels];
                         for (int i = 0; i < num_channels; i++) {
@@ -151,14 +193,56 @@
 
     }
 
+    /** information element from beacon */
     public static class InformationElement {
         public int id;
         public byte[] bytes;
     }
 
-    public static class FullScanResult {
+    /** scan result with information elements from beacons */
+    public static class FullScanResult implements Parcelable {
         public ScanResult result;
         public InformationElement informationElements[];
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            result.writeToParcel(dest, flags);
+            dest.writeInt(informationElements.length);
+            for (int i = 0; i < informationElements.length; i++) {
+                dest.writeInt(informationElements[i].id);
+                dest.writeInt(informationElements[i].bytes.length);
+                dest.writeByteArray(informationElements[i].bytes);
+            }
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<FullScanResult> CREATOR =
+                new Creator<FullScanResult>() {
+                    public FullScanResult createFromParcel(Parcel in) {
+                        FullScanResult result = new FullScanResult();
+                        result.result = ScanResult.CREATOR.createFromParcel(in);
+                        int n = in.readInt();
+                        result.informationElements = new InformationElement[n];
+                        for (int i = 0; i < n; i++) {
+                            result.informationElements[i] = new InformationElement();
+                            result.informationElements[i].id = in.readInt();
+                            int len = in.readInt();
+                            result.informationElements[i].bytes = new byte[len];
+                            in.readByteArray(result.informationElements[i].bytes);
+                        }
+
+                        return result;
+                    }
+
+                    public FullScanResult[] newArray(int size) {
+                        return new FullScanResult[size];
+                    }
+                };
     }
 
     /** @hide */
@@ -206,88 +290,210 @@
     }
 
     /**
-     * Framework is co-ordinating scans across multiple apps; so it may not give exactly the
-     * same period requested. The period granted is stated on the onSuccess() event; and
-     * onPeriodChanged() will be called if/when it is changed because of multiple conflicting
-     * requests. This is similar to the way timers are handled.
+     * interface to get scan events on; specify this on {@link #startBackgroundScan}
      */
     public interface ScanListener extends ActionListener {
+        /**
+         * Framework co-ordinates scans across multiple apps; so it may not give exactly the
+         * same period requested. If period of a scan is changed; it is reported by this event.
+         */
         public void onPeriodChanged(int periodInMs);
+        /**
+         * reports results retrieved from background scan
+         */
         public void onResults(ScanResult[] results);
+        /**
+         * reports full scan result for each access point found in scan
+         */
         public void onFullResult(FullScanResult fullScanResult);
     }
 
+    /** @hide */
     public void scan(ScanSettings settings, ScanListener listener) {
         validateChannel();
         sAsyncChannel.sendMessage(CMD_SCAN, 0, putListener(listener), settings);
     }
+
+    /** start wifi scan in background
+     * @param settings specifies various parameters for the scan; for more information look at
+     * {@link ScanSettings}
+     * @param listener specifies the object to report events to. This object is also treated as a
+     *                 key for this scan, and must also be specified to cancel the scan. Multiple
+     *                 scans should also not share this object.
+     */
     public void startBackgroundScan(ScanSettings settings, ScanListener listener) {
         validateChannel();
         sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, putListener(listener), settings);
     }
-    public void stopBackgroundScan(boolean flush, ScanListener listener) {
+    /**
+     * stop an ongoing wifi scan
+     * @param listener specifies which scan to cancel; must be same object as passed in {@link
+     *  #startBackgroundScan}
+     */
+    public void stopBackgroundScan(ScanListener listener) {
         validateChannel();
         sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, removeListener(listener));
     }
+    /**
+     * retrieves currently available scan results
+     * @param flush {@code true} means flush all results
+     * @param listener specifies which scan to cancel; must be same object as passed in {@link
+     *                 #startBackgroundScan}
+     */
     public void retrieveScanResults(boolean flush, ScanListener listener) {
         validateChannel();
         sAsyncChannel.sendMessage(CMD_GET_SCAN_RESULTS, 0, getListenerKey(listener));
     }
 
+    /** specifies information about an access point of interest */
     public static class HotspotInfo {
+        /** bssid of the access point; in XX:XX:XX:XX:XX:XX format */
         public String bssid;
+        /** low signal strength threshold; more information at {@link ScanResult#level} */
         public int low;                                            /* minimum RSSI */
+        /** high signal threshold; more information at {@link ScanResult#level} */
         public int high;                                           /* maximum RSSI */
+        /** channel frequency (in KHz) where you may find this BSSID */
+        public int frequencyHint;
     }
 
-    public static class WifiChangeSettings {
-        public int rssiSampleSize;                                 /* sample size for RSSI averaging */
-        public int lostApSampleSize;                               /* samples to confirm AP's loss */
-        public int unchangedSampleSize;                            /* samples to confirm no change */
-        public int minApsBreachingThreshold;                       /* change threshold to trigger event */
+    /** @hide */
+    public static class WifiChangeSettings implements Parcelable {
+        public int rssiSampleSize;                          /* sample size for RSSI averaging */
+        public int lostApSampleSize;                        /* samples to confirm AP's loss */
+        public int unchangedSampleSize;                     /* samples to confirm no change */
+        public int minApsBreachingThreshold;                /* change threshold to trigger event */
+        public int periodInMs;                              /* scan period in millisecond */
         public HotspotInfo[] hotspotInfos;
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(rssiSampleSize);
+            dest.writeInt(lostApSampleSize);
+            dest.writeInt(unchangedSampleSize);
+            dest.writeInt(minApsBreachingThreshold);
+            dest.writeInt(periodInMs);
+            dest.writeInt(hotspotInfos.length);
+            for (int i = 0; i < hotspotInfos.length; i++) {
+                HotspotInfo info = hotspotInfos[i];
+                dest.writeString(info.bssid);
+                dest.writeInt(info.low);
+                dest.writeInt(info.high);
+                dest.writeInt(info.frequencyHint);
+            }
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<WifiChangeSettings> CREATOR =
+                new Creator<WifiChangeSettings>() {
+                    public WifiChangeSettings createFromParcel(Parcel in) {
+                        WifiChangeSettings settings = new WifiChangeSettings();
+                        settings.rssiSampleSize = in.readInt();
+                        settings.lostApSampleSize = in.readInt();
+                        settings.unchangedSampleSize = in.readInt();
+                        settings.minApsBreachingThreshold = in.readInt();
+                        settings.periodInMs = in.readInt();
+                        int len = in.readInt();
+                        settings.hotspotInfos = new HotspotInfo[len];
+                        for (int i = 0; i < len; i++) {
+                            HotspotInfo info = new HotspotInfo();
+                            info.bssid = in.readString();
+                            info.low = in.readInt();
+                            info.high = in.readInt();
+                            info.frequencyHint = in.readInt();
+                            settings.hotspotInfos[i] = info;
+                        }
+                        return settings;
+                    }
+
+                    public WifiChangeSettings[] newArray(int size) {
+                        return new WifiChangeSettings[size];
+                    }
+                };
+
     }
 
-    /* overrides the significant wifi change state machine configuration */
-    public void configureSignificantWifiChange(
+    /** configure WifiChange detection
+     * @param rssiSampleSize number of samples used for RSSI averaging
+     * @param lostApSampleSize number of samples to confirm an access point's loss
+     * @param unchangedSampleSize number of samples to confirm there are no changes
+     * @param minApsBreachingThreshold minimum number of access points that need to be
+     *                                 out of range to detect WifiChange
+     * @param periodInMs indicates period of scan to find changes
+     * @param hotspotInfos access points to watch
+     */
+    public void configureWifiChange(
             int rssiSampleSize,                             /* sample size for RSSI averaging */
             int lostApSampleSize,                           /* samples to confirm AP's loss */
             int unchangedSampleSize,                        /* samples to confirm no change */
             int minApsBreachingThreshold,                   /* change threshold to trigger event */
+            int periodInMs,                                 /* period of scan */
             HotspotInfo[] hotspotInfos                      /* signal thresholds to crosss */
             )
     {
         validateChannel();
+
         WifiChangeSettings settings = new WifiChangeSettings();
         settings.rssiSampleSize = rssiSampleSize;
         settings.lostApSampleSize = lostApSampleSize;
         settings.unchangedSampleSize = unchangedSampleSize;
         settings.minApsBreachingThreshold = minApsBreachingThreshold;
+        settings.periodInMs = periodInMs;
         settings.hotspotInfos = hotspotInfos;
 
-        sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+        configureWifiChange(settings);
     }
 
-    public interface SignificantWifiChangeListener extends ActionListener {
+    /**
+     * interface to get wifi change events on; use this on {@link #startTrackingWifiChange}
+     */
+    public interface WifiChangeListener extends ActionListener {
+        /** indicates that changes were detected in wifi environment
+         * @param results indicate the access points that exhibited change
+         */
         public void onChanging(ScanResult[] results);           /* changes are found */
+        /** indicates that no wifi changes are being detected for a while
+         * @param results indicate the access points that are bing monitored for change
+         */
         public void onQuiescence(ScanResult[] results);         /* changes settled down */
     }
 
-    public void trackSignificantWifiChange(SignificantWifiChangeListener listener) {
+    /**
+     * track changes in wifi environment
+     * @param listener object to report events on; this object must be unique and must also be
+     *                 provided on {@link #stopTrackingWifiChange}
+     */
+    public void startTrackingWifiChange(WifiChangeListener listener) {
         validateChannel();
         sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, putListener(listener));
     }
-    public void untrackSignificantWifiChange(SignificantWifiChangeListener listener) {
+
+    /**
+     * stop tracking changes in wifi environment
+     * @param listener object that was provided to report events on {@link
+     * #stopTrackingWifiChange}
+     */
+    public void stopTrackingWifiChange(WifiChangeListener listener) {
         validateChannel();
         sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, removeListener(listener));
     }
 
-    public void configureSignificantWifiChange(WifiChangeSettings settings) {
+    /** @hide */
+    public void configureWifiChange(WifiChangeSettings settings) {
         validateChannel();
         sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
     }
 
+    /** interface to receive hotlist events on; use this on {@link #setHotlist} */
     public static interface HotlistListener extends ActionListener {
+        /** indicates that access points were found by on going scans
+         * @param results list of scan results, one for each access point visible currently
+         */
         public void onFound(ScanResult[] results);
     }
 
@@ -310,6 +516,7 @@
                 dest.writeString(info.bssid);
                 dest.writeInt(info.low);
                 dest.writeInt(info.high);
+                dest.writeInt(info.frequencyHint);
             }
         }
 
@@ -326,6 +533,7 @@
                             info.bssid = in.readString();
                             info.low = in.readInt();
                             info.high = in.readInt();
+                            info.frequencyHint = in.readInt();
                             settings.hotspotInfos[i] = info;
                         }
                         return settings;
@@ -337,6 +545,13 @@
                 };
     }
 
+    /**
+     * set interesting access points to find
+     * @param hotspots access points of interest
+     * @param apLostThreshold number of scans needed to indicate that AP is lost
+     * @param listener object provided to report events on; this object must be unique and must
+     *                 also be provided on {@link #resetHotlist}
+     */
     public void setHotlist(HotspotInfo[] hotspots,
             int apLostThreshold, HotlistListener listener) {
         validateChannel();
@@ -345,6 +560,10 @@
         sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, putListener(listener), settings);
     }
 
+    /**
+     * remove tracking of interesting access points
+     * @param listener same object provided in {@link #setHotlist}
+     */
     public void resetHotlist(HotlistListener listener) {
         validateChannel();
         sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, removeListener(listener));
@@ -554,6 +773,7 @@
                     break;
                 case CMD_OP_FAILED :
                     ((ActionListener) listener).onFailure(msg.arg1, msg.obj);
+                    removeListener(msg.arg2);
                     break;
                 case CMD_SCAN_RESULT :
                     ((ScanListener) listener).onResults(
@@ -568,11 +788,11 @@
                             ((ParcelableScanResults) msg.obj).getResults());
                     return;
                 case CMD_WIFI_CHANGE_DETECTED:
-                    ((SignificantWifiChangeListener) listener).onChanging(
+                    ((WifiChangeListener) listener).onChanging(
                             ((ParcelableScanResults) msg.obj).getResults());
                    return;
                 case CMD_WIFI_CHANGES_STABILIZED:
-                    ((SignificantWifiChangeListener) listener).onQuiescence(
+                    ((WifiChangeListener) listener).onQuiescence(
                             ((ParcelableScanResults) msg.obj).getResults());
                     return;
                 default:
diff --git a/wifi/java/android/net/wifi/hotspot/WifiHotspotManager.java b/wifi/java/android/net/wifi/hotspot/WifiHotspotManager.java
deleted file mode 100644
index ac15017..0000000
--- a/wifi/java/android/net/wifi/hotspot/WifiHotspotManager.java
+++ /dev/null
@@ -1,48 +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 android.net.wifi.hotspot;
-
-import android.content.Context;
-import android.os.RemoteException;
-import android.util.Log;
-
-/**
- * TODO: doc
- */
-public class WifiHotspotManager {
-
-    private static final String TAG = "WifiHotspotManager";
-
-    private Context mContext;
-    IWifiHotspotManager mService;
-
-    public WifiHotspotManager(Context context, IWifiHotspotManager service) {
-        mContext = context;
-        mService = service;
-    }
-
-    public void test() {
-        try{
-            Log.d(TAG, "test()");
-            mService.test();
-        }
-        catch (RemoteException e) {
-            Log.e(TAG, "test() exception");
-            e.printStackTrace();
-        }
-    }
-}
diff --git a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl b/wifi/java/android/net/wifi/passpoint/IPasspointManager.aidl
similarity index 73%
copy from wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
copy to wifi/java/android/net/wifi/passpoint/IPasspointManager.aidl
index 2b1601b..e57db64 100644
--- a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/IPasspointManager.aidl
@@ -14,15 +14,18 @@
  * limitations under the License.
  */
 
-package android.net.wifi.hotspot;
+package android.net.wifi.passpoint;
+
+import android.os.Messenger;
 
 /**
- * Interface that allows controlling and querying Hotspot connectivity.
+ * Interface that allows controlling and querying Passpoint connectivity.
  *
  * {@hide}
  */
-interface IWifiHotspotManager
+interface IPasspointManager
 {
-    void test();
+    Messenger getMessenger();
+    int getPasspointState();
 }
 
diff --git a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl b/wifi/java/android/net/wifi/passpoint/PasspointCredential.aidl
similarity index 77%
copy from wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
copy to wifi/java/android/net/wifi/passpoint/PasspointCredential.aidl
index 2b1601b..6f75cbe 100644
--- a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/PasspointCredential.aidl
@@ -14,15 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.hotspot;
+package android.net.wifi.passpoint;
 
-/**
- * Interface that allows controlling and querying Hotspot connectivity.
- *
- * {@hide}
- */
-interface IWifiHotspotManager
-{
-    void test();
-}
-
+parcelable PasspointCredential;
diff --git a/wifi/java/android/net/wifi/passpoint/PasspointCredential.java b/wifi/java/android/net/wifi/passpoint/PasspointCredential.java
new file mode 100644
index 0000000..4218f23
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/PasspointCredential.java
@@ -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.
+ */
+
+package android.net.wifi.passpoint;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+public class PasspointCredential implements Parcelable {
+
+    @Override
+    public String toString() {
+        // TODO
+        return null;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        // TODO
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public static final Creator<PasspointCredential> CREATOR =
+            new Creator<PasspointCredential>() {
+                @Override
+                public PasspointCredential createFromParcel(Parcel in) {
+                    // TODO
+                    return null;
+                }
+
+                @Override
+                public PasspointCredential[] newArray(int size) {
+                    return new PasspointCredential[size];
+                }
+            };
+}
diff --git a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl b/wifi/java/android/net/wifi/passpoint/PasspointInfo.aidl
similarity index 77%
copy from wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
copy to wifi/java/android/net/wifi/passpoint/PasspointInfo.aidl
index 2b1601b..cc11045 100644
--- a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/PasspointInfo.aidl
@@ -14,15 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.hotspot;
+package android.net.wifi.passpoint;
 
-/**
- * Interface that allows controlling and querying Hotspot connectivity.
- *
- * {@hide}
- */
-interface IWifiHotspotManager
-{
-    void test();
-}
-
+parcelable PasspointInfo;
diff --git a/wifi/java/android/net/wifi/passpoint/PasspointInfo.java b/wifi/java/android/net/wifi/passpoint/PasspointInfo.java
new file mode 100644
index 0000000..d57b0aa
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/PasspointInfo.java
@@ -0,0 +1,274 @@
+/*
+ * 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.net.wifi.passpoint;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * TODO: doc
+ */
+public class PasspointInfo implements Parcelable {
+
+    /** TODO doc */
+    public static final int ANQP_CAPABILITY             = 1 << 0;
+
+    /** TODO doc */
+    public static final int VENUE_NAME                  = 1 << 1;
+
+    /** TODO doc */
+    public static final int NETWORK_AUTH_TYPE           = 1 << 2;
+
+    /** TODO doc */
+    public static final int ROAMING_CONSORTIUM          = 1 << 3;
+
+    /** TODO doc */
+    public static final int IP_ADDR_TYPE_AVAILABILITY   = 1 << 4;
+
+    /** TODO doc */
+    public static final int NAI_REALM                   = 1 << 5;
+
+    /** TODO doc */
+    public static final int CELLULAR_NETWORK            = 1 << 6;
+
+    /** TODO doc */
+    public static final int DOMAIN_NAME                 = 1 << 7;
+
+    /** TODO doc */
+    public static final int HOTSPOT_CAPABILITY          = 1 << 8;
+
+    /** TODO doc */
+    public static final int OPERATOR_FRIENDLY_NAME      = 1 << 9;
+
+    /** TODO doc */
+    public static final int WAN_METRICS                 = 1 << 10;
+
+    /** TODO doc */
+    public static final int CONNECTION_CAPABILITY       = 1 << 11;
+
+    /** TODO doc */
+    public static final int OSU_PROVIDER                = 1 << 12;
+
+    /** TODO doc */
+    public static final int PRESET_CRED_MATCH =
+            ANQP_CAPABILITY |
+            HOTSPOT_CAPABILITY |
+            NAI_REALM |
+            CELLULAR_NETWORK |
+            DOMAIN_NAME;
+
+    /** TODO doc */
+    public static final int PRESET_ALL =
+            ANQP_CAPABILITY |
+            VENUE_NAME |
+            NETWORK_AUTH_TYPE |
+            ROAMING_CONSORTIUM |
+            IP_ADDR_TYPE_AVAILABILITY |
+            NAI_REALM |
+            CELLULAR_NETWORK |
+            DOMAIN_NAME |
+            HOTSPOT_CAPABILITY |
+            OPERATOR_FRIENDLY_NAME |
+            WAN_METRICS |
+            CONNECTION_CAPABILITY |
+            OSU_PROVIDER;
+
+
+    /** TODO doc */
+    public String bssid;
+
+    /** TODO doc */
+    public String venueName;
+
+    /** TODO doc */
+    public String networkAuthType;
+
+    /** TODO doc */
+    public String roamingConsortium;
+
+    /** TODO doc */
+    public String ipAddrTypeAvaibility;
+
+    /** TODO doc */
+    public String naiRealm;
+
+    /** TODO doc */
+    public String cellularNetwork;
+
+    /** TODO doc */
+    public String domainName;
+
+    /** TODO doc */
+    public String operatorFriendlyName;
+
+    /** TODO doc */
+    public String wanMetrics;
+
+    /** TODO doc */
+    public String connectionCapability;
+
+    /** TODO doc */
+    public List<PasspointOsuProvider> osuProviderList;
+
+
+    /** default constructor @hide */
+    public PasspointInfo() {
+//        osuProviderList = new ArrayList<OsuProvider>();
+    }
+
+    /** copy constructor @hide */
+    public PasspointInfo(PasspointInfo source) {
+        // TODO
+        bssid = source.bssid;
+        venueName = source.venueName;
+        networkAuthType = source.networkAuthType;
+        roamingConsortium = source.roamingConsortium;
+        ipAddrTypeAvaibility = source.ipAddrTypeAvaibility;
+        naiRealm = source.naiRealm;
+        cellularNetwork = source.cellularNetwork;
+        domainName = source.domainName;
+        operatorFriendlyName = source.operatorFriendlyName;
+        wanMetrics = source.wanMetrics;
+        connectionCapability = source.connectionCapability;
+        if (source.osuProviderList != null) {
+            osuProviderList = new ArrayList<PasspointOsuProvider>();
+            for (PasspointOsuProvider osu : source.osuProviderList)
+                osuProviderList.add(new PasspointOsuProvider(osu));
+        }
+    }
+
+    /**
+     * Convert mask to ANQP subtypes, for supplicant command use.
+     *
+     * @param mask The ANQP subtypes mask.
+     * @return String of ANQP subtypes, good for supplicant command use
+     * @hide
+     */
+    public static String toAnqpSubtypes(int mask) {
+        StringBuilder sb = new StringBuilder();
+        if ((mask & ANQP_CAPABILITY) != 0) sb.append("257,");
+        if ((mask & VENUE_NAME) != 0) sb.append("258,");
+        if ((mask & NETWORK_AUTH_TYPE) != 0) sb.append("260,");
+        if ((mask & ROAMING_CONSORTIUM) != 0) sb.append("261,");
+        if ((mask & IP_ADDR_TYPE_AVAILABILITY) != 0) sb.append("262,");
+        if ((mask & NAI_REALM) != 0) sb.append("263,");
+        if ((mask & CELLULAR_NETWORK) != 0) sb.append("264,");
+        if ((mask & DOMAIN_NAME) != 0) sb.append("268,");
+        if ((mask & HOTSPOT_CAPABILITY) != 0) sb.append("hs20:2,");
+        if ((mask & OPERATOR_FRIENDLY_NAME) != 0) sb.append("hs20:3,");
+        if ((mask & WAN_METRICS) != 0) sb.append("hs20:4,");
+        if ((mask & CONNECTION_CAPABILITY) != 0) sb.append("hs20:5,");
+        if ((mask & OSU_PROVIDER) != 0) sb.append("hs20:8,");
+        if (sb.length() > 0) sb.deleteCharAt(sb.length() - 1);
+        return sb.toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("BSSID: ").append(bssid);
+        if (venueName != null)
+            sb.append(" venueName: ").append(venueName);
+        if (networkAuthType != null)
+            sb.append(" networkAuthType: ").append(networkAuthType);
+        if (roamingConsortium != null)
+            sb.append(" roamingConsortium: ").append(roamingConsortium);
+        if (ipAddrTypeAvaibility != null)
+            sb.append(" ipAddrTypeAvaibility: ").append(ipAddrTypeAvaibility);
+        if (naiRealm != null)
+            sb.append(" naiRealm: ").append(naiRealm);
+        if (cellularNetwork != null)
+            sb.append(" cellularNetwork: ").append(cellularNetwork);
+        if (domainName != null)
+            sb.append(" domainName: ").append(domainName);
+        if (operatorFriendlyName != null)
+            sb.append(" operatorFriendlyName: ").append(operatorFriendlyName);
+        if (wanMetrics != null)
+            sb.append(" wanMetrics: ").append(wanMetrics);
+        if (connectionCapability != null)
+            sb.append(" connectionCapability: ").append(connectionCapability);
+        if (osuProviderList != null)
+            sb.append(" osuProviderList: (size=" + osuProviderList.size() + ")");
+        return sb.toString();
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeValue(bssid);
+        out.writeValue(venueName);
+        out.writeValue(networkAuthType);
+        out.writeValue(roamingConsortium);
+        out.writeValue(ipAddrTypeAvaibility);
+        out.writeValue(naiRealm);
+        out.writeValue(cellularNetwork);
+        out.writeValue(domainName);
+        out.writeValue(operatorFriendlyName);
+        out.writeValue(wanMetrics);
+        out.writeValue(connectionCapability);
+        if (osuProviderList == null) {
+            out.writeInt(0);
+        } else {
+            out.writeInt(osuProviderList.size());
+            for (PasspointOsuProvider osu : osuProviderList)
+                osu.writeToParcel(out, flags);
+        }
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public static final Parcelable.Creator<PasspointInfo> CREATOR =
+            new Parcelable.Creator<PasspointInfo>() {
+        @Override
+        public PasspointInfo createFromParcel(Parcel in) {
+            PasspointInfo p = new PasspointInfo();
+            p.bssid = (String) in.readValue(String.class.getClassLoader());
+            p.venueName = (String) in.readValue(String.class.getClassLoader());
+            p.networkAuthType = (String) in.readValue(String.class.getClassLoader());
+            p.roamingConsortium = (String) in.readValue(String.class.getClassLoader());
+            p.ipAddrTypeAvaibility = (String) in.readValue(String.class.getClassLoader());
+            p.naiRealm = (String) in.readValue(String.class.getClassLoader());
+            p.cellularNetwork = (String) in.readValue(String.class.getClassLoader());
+            p.domainName = (String) in.readValue(String.class.getClassLoader());
+            p.operatorFriendlyName = (String) in.readValue(String.class.getClassLoader());
+            p.wanMetrics = (String) in.readValue(String.class.getClassLoader());
+            p.connectionCapability = (String) in.readValue(String.class.getClassLoader());
+            int n = in.readInt();
+            if (n > 0) {
+                p.osuProviderList = new ArrayList<PasspointOsuProvider>();
+                for (int i = 0; i < n; i++) {
+                    PasspointOsuProvider osu = PasspointOsuProvider.CREATOR.createFromParcel(in);
+                    p.osuProviderList.add(osu);
+                }
+            }
+            return p;
+        }
+
+        @Override
+        public PasspointInfo[] newArray(int size) {
+            return new PasspointInfo[size];
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/passpoint/PasspointManager.java b/wifi/java/android/net/wifi/passpoint/PasspointManager.java
new file mode 100644
index 0000000..234a44c
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/PasspointManager.java
@@ -0,0 +1,504 @@
+/*
+ * 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.net.wifi.passpoint;
+
+import android.content.Context;
+import android.net.wifi.ScanResult;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Protocol;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * TODO: doc
+ */
+public class PasspointManager {
+
+    private static final String TAG = "PasspointManager";
+
+    private static final boolean DBG = true;
+
+    /* Passpoint states values */
+
+    /** Passpoint is in an known state. This should only occur in boot time */
+    public static final int PASSPOINT_STATE_UNKNOWN     = 0;
+
+    /** Passpoint is disabled. This occurs when wifi is disabled. */
+    public static final int PASSPOINT_STATE_DISABLED    = 1;
+
+    /** Passpoint is enabled and in discovery state. */
+    public static final int PASSPOINT_STATE_DISCOVERY   = 2;
+
+    /** Passpoint is enabled and in access state. */
+    public static final int PASSPOINT_STATE_ACCESS      = 3;
+
+    /** Passpoint is enabled and in provisioning state. */
+    public static final int PASSPOINT_STATE_PROVISION   = 4;
+
+    /* Passpoint callback error codes */
+
+    /** Indicates that the operation failed due to an internal error */
+    public static final int ERROR           = 0;
+
+    /** Indicates that the operation failed because wifi is disabled */
+    public static final int WIFI_DISABLED   = 1;
+
+    /** Indicates that the operation failed because the framework is busy */
+    public static final int BUSY            = 2;
+
+    /* Passpoint broadcasts */
+
+    /**
+     * Broadcast intent action indicating that the state of Passpoint
+     * connectivity has changed
+     */
+    public static final String PASSPOINT_STATE_CHANGED_ACTION =
+            "android.net.wifi.passpoint.STATE_CHANGE";
+
+    /**
+     * Broadcast intent action indicating that the saved Passpoint credential
+     * list has changed
+     */
+    public static final String PASSPOINT_CRED_CHANGED_ACTION =
+            "android.net.wifi.passpoint.CRED_CHANGE";
+
+    /**
+     * Broadcast intent action indicating that Passpoint online sign up is
+     * avaiable.
+     * @hide
+     */
+    public static final String PASSPOINT_OSU_AVAILABLE_ACTION =
+            "android.net.wifi.passpoint.OSU_AVAILABLE";
+
+    /**
+     * Broadcast intent action indicating that user remediation is required
+     * @hide
+     */
+    public static final String PASSPOINT_USER_REM_REQ_ACTION =
+            "android.net.wifi.passpoint.USER_REM_REQ";
+
+
+    /**
+     * Interface for callback invocation when framework channel is lost
+     */
+    public interface ChannelListener {
+        /**
+         * The channel to the framework has been disconnected. Application could
+         * try re-initializing using {@link #initialize}
+         */
+        public void onChannelDisconnected();
+    }
+
+    /**
+     * Interface for callback invocation on an application action
+     */
+    public interface ActionListener {
+        /** The operation succeeded */
+        public void onSuccess();
+
+        /**
+         * * The operation failed
+         *
+         * @param reason The reason for failure could be one of
+         *            {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
+         */
+        public void onFailure(int reason);
+    }
+
+    /**
+     * Interface for callback invocation when doing OSU or user remediation
+     * @hide
+     */
+    public interface OsuRemListener {
+        /** The operation succeeded */
+        public void onSuccess();
+
+        /**
+         * The operation failed
+         *
+         * @param reason The reason for failure could be one of
+         *            {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
+         */
+        public void onFailure(int reason);
+
+        /**
+         * Browser launch is requried for user interaction. When this callback
+         * is called, app should launch browser / webview to the given URL.
+         *
+         * @param url URL for browser launch
+         */
+        public void onBrowserLaunch(String url);
+
+        /**
+         * When this is called, app should dismiss the previously lanched browser.
+         */
+        public void onBrowserDismiss();
+    }
+
+    /**
+     * A channel that connects the application to the wifi passpoint framework.
+     * Most passpoint operations require a Channel as an argument.
+     * An instance of Channel is obtained by doing a call on {@link #initialize}
+     */
+    public static class Channel {
+        private final static int INVALID_LISTENER_KEY = 0;
+
+        private ChannelListener mChannelListener;
+
+        private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
+        private HashMap<Integer, Integer> mListenerMapCount = new HashMap<Integer, Integer>();
+        private Object mListenerMapLock = new Object();
+        private int mListenerKey = 0;
+
+        private List<ScanResult> mAnqpRequest = new LinkedList<ScanResult>();
+        private Object mAnqpRequestLock = new Object();
+
+        private AsyncChannel mAsyncChannel;
+        private PasspointHandler mHandler;
+        Context mContext;
+
+        Channel(Context context, Looper looper, ChannelListener l) {
+            mAsyncChannel = new AsyncChannel();
+            mHandler = new PasspointHandler(looper);
+            mChannelListener = l;
+            mContext = context;
+        }
+
+        private int putListener(Object listener) {
+            return putListener(listener, 1);
+        }
+
+        private int putListener(Object listener, int count) {
+            if (listener == null || count <= 0) return INVALID_LISTENER_KEY;
+            int key;
+            synchronized (mListenerMapLock) {
+                do {
+                    key = mListenerKey++;
+                } while (key == INVALID_LISTENER_KEY);
+                mListenerMap.put(key, listener);
+                mListenerMapCount.put(key, count);
+            }
+            return key;
+        }
+
+        private Object getListener(int key, boolean force) {
+            Log.d(TAG, "getListener() key=" + key + " force=" + force);
+            if (key == INVALID_LISTENER_KEY) return null;
+            synchronized (mListenerMapLock) {
+                if (!force) {
+                    int count = mListenerMapCount.get(key);
+                    Log.d(TAG, "count=" + count);
+                    mListenerMapCount.put(key, --count);
+                    if (count > 0) return null;
+                }
+                Log.d(TAG, "remove key");
+                mListenerMapCount.remove(key);
+                return mListenerMap.remove(key);
+            }
+        }
+
+        private void anqpRequestStart(ScanResult sr) {
+            Log.d(TAG, "anqpRequestStart sr.bssid=" + sr.BSSID);
+            synchronized(mAnqpRequestLock) { mAnqpRequest.add(sr); }
+        }
+
+        private void anqpRequestFinish(PasspointInfo result) {
+            Log.d(TAG, "anqpRequestFinish pi.bssid=" + result.bssid);
+            synchronized(mAnqpRequestLock) {
+                for (ScanResult sr : mAnqpRequest)
+                    if (sr.BSSID.equals(result.bssid)) {
+                        Log.d(TAG, "find hit " + result.bssid);
+                        sr.passpoint = result;
+                        mAnqpRequest.remove(sr);
+                        Log.d(TAG, "mAnqpRequest.len=" + mAnqpRequest.size());
+                        break;
+                    }
+            }
+        }
+
+        private void anqpRequestFinish(ScanResult sr) {
+            Log.d(TAG, "anqpRequestFinish sr.bssid=" + sr.BSSID);
+            synchronized(mAnqpRequestLock) {
+                for (ScanResult sr1 : mAnqpRequest)
+                    if (sr1.BSSID.equals(sr.BSSID)) {
+                        mAnqpRequest.remove(sr1);
+                        break;
+                    }
+            }
+        }
+
+        class PasspointHandler extends Handler {
+            PasspointHandler(Looper looper) {
+                super(looper);
+            }
+
+            @Override
+            public void handleMessage(Message message) {
+                Object listener = getListener(message.arg2, false);
+                switch (message.what) {
+                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+                        if (mChannelListener != null) {
+                            mChannelListener.onChannelDisconnected();
+                            mChannelListener = null;
+                        }
+                        break;
+
+                    case REQUEST_ANQP_INFO_SUCCEEDED:
+                        PasspointInfo result = (PasspointInfo) message.obj;
+                        anqpRequestFinish(result);
+                        if (listener != null) {
+                            ((ActionListener) listener).onSuccess();
+                        }
+                        break;
+
+                    case REQUEST_ANQP_INFO_FAILED:
+                        anqpRequestFinish((ScanResult) message.obj);
+                        if (listener == null) getListener(message.arg2, true);
+                        if (listener != null) {
+                            ((ActionListener) listener).onFailure(message.arg1);
+                        }
+                        break;
+
+                    default:
+                        Log.d(TAG, "Ignored " + message);
+                        break;
+                }
+            }
+        }
+
+    }
+
+
+    private static final int BASE = Protocol.BASE_WIFI_PASSPOINT_MANAGER;
+
+    /** @hide */
+    public static final int REQUEST_ANQP_INFO                       = BASE + 1;
+
+    /** @hide */
+    public static final int REQUEST_ANQP_INFO_FAILED                = BASE + 2;
+
+    /** @hide */
+    public static final int REQUEST_ANQP_INFO_SUCCEEDED             = BASE + 3;
+
+    /** @hide */
+    public static final int REQUEST_OSU_INFO                        = BASE + 4;
+
+    /** @hide */
+    public static final int REQUEST_OSU_INFO_FAILED                 = BASE + 5;
+
+    /** @hide */
+    public static final int REQUEST_OSU_INFO_SUCCEEDED              = BASE + 6;
+
+
+    private Context mContext;
+    IPasspointManager mService;
+
+
+    /**
+     * TODO: doc
+     * @param context
+     * @param service
+     */
+    public PasspointManager(Context context, IPasspointManager service) {
+        mContext = context;
+        mService = service;
+    }
+
+    /**
+     * Registers the application with the framework. This function must be the
+     * first to be called before any async passpoint operations are performed.
+     *
+     * @param srcContext is the context of the source
+     * @param srcLooper is the Looper on which the callbacks are receivied
+     * @param listener for callback at loss of framework communication. Can be
+     *            null.
+     * @return Channel instance that is necessary for performing any further
+     *         passpoint operations
+     */
+    public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
+        Messenger messenger = getMessenger();
+        if (messenger == null) return null;
+
+        Channel c = new Channel(srcContext, srcLooper, listener);
+        if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
+                == AsyncChannel.STATUS_SUCCESSFUL) {
+            return c;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * STOPSHIP: temp solution, should use supplicant manager instead, check
+     * with b/13931972
+     *
+     * @hide
+     */
+    public Messenger getMessenger() {
+        try {
+            return mService.getMessenger();
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Get Passpoint state.
+     *
+     * @return One of {@link #PASSPOINT_STATE_DISABLED},
+     *         {@link #PASSPOINT_STATE_DISCOVERY},
+     *         {@link #PASSPOINT_STATE_ACCESS},
+     *         {@link #PASSPOINT_STATE_PROVISION},
+     *         {@link #PASSPOINT_STATE_UNKNOWN}
+     */
+    public int getPasspointState() {
+        try{
+            return mService.getPasspointState();
+        }
+        catch (RemoteException e) {
+            return PASSPOINT_STATE_UNKNOWN;
+        }
+    }
+
+    /**
+     * TODO: doc
+     *
+     * @param c
+     * @param requested
+     * @param mask
+     * @param listener
+     *
+     * @hide
+     */
+    public void requestAnqpInfo(Channel c, List<ScanResult> requested, int mask,
+            ActionListener listener) {
+        Log.d(TAG, "requestAnqpInfo start");
+        Log.d(TAG, "requested.size=" + requested.size());
+        checkChannel(c);
+        List<ScanResult> list = new ArrayList<ScanResult>();
+        for (ScanResult sr : requested) if (sr.capabilities.contains("[HS20]")) {
+            list.add(sr);
+            c.anqpRequestStart(sr);
+            Log.d(TAG, "adding " + sr.BSSID);
+        }
+        int count = list.size();
+        Log.d(TAG, "after filter, count=" + count);
+        if (count == 0) {
+            if (DBG) Log.d(TAG, "ANQP info request contains no HS20 APs, skipped");
+            listener.onSuccess();
+            return;
+        }
+        int key = c.putListener(listener, count);
+        for (ScanResult sr : list)
+            c.mAsyncChannel.sendMessage(REQUEST_ANQP_INFO, mask, key, sr);
+        Log.d(TAG, "requestAnqpInfo end");
+    }
+
+    /**
+     * TODO: doc
+     *
+     * @param c
+     * @param requested
+     * @param resolution
+     * @param listener
+     */
+    public void requestOsuIcons(Channel c, List<PasspointOsuProvider> requested,
+            int resolution, ActionListener listener) {
+    }
+
+    /**
+     * TODO: doc
+     *
+     * @param requested
+     * @return
+     */
+    public List<PasspointPolicy> requestCredentialMatch(List<ScanResult> requested) {
+        return null;
+    }
+
+    /* TODO: add credential APIs */
+
+    /**
+     * Give a list of all saved Passpoint credentials.
+     *
+     * @return The list of credentials
+     */
+    public List<PasspointCredential> getSavedCredentials() {
+        return null;
+    }
+
+    /**
+     * Add a new Passpoint credential.
+     *
+     * @param cred The credential to be added
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
+    public boolean addCredential(PasspointCredential cred) {
+        return true;
+    }
+
+    /**
+     * Update an existing Passpoint credential.
+     *
+     * @param cred The credential to be updated
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
+    public boolean updateCredential(PasspointCredential cred) {
+        return true;
+    }
+
+    /**
+     * Remove an existing Passpoint credential.
+     *
+     * @param cred The credential to be removed
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
+    public boolean removeCredential(PasspointCredential cred) {
+        return true;
+    }
+
+    /** @hide */
+    public void startOsu(Channel c, PasspointOsuProvider selected, OsuRemListener listener) {
+
+    }
+
+    /** @hide */
+    public void startUserRemediation(Channel c, OsuRemListener listener) {
+    }
+
+    /**
+     * Select and connect to a Passpoint network.
+     *
+     * @param selected Selected Passpoint network, see {@link PasspointPolicy}
+     */
+    public void connect(PasspointPolicy selected) {
+    }
+
+    private static void checkChannel(Channel c) {
+        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+    }
+}
diff --git a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl b/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.aidl
similarity index 77%
rename from wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
rename to wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.aidl
index 2b1601b..f5ecb7c 100644
--- a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.aidl
@@ -14,15 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.hotspot;
+package android.net.wifi.passpoint;
 
-/**
- * Interface that allows controlling and querying Hotspot connectivity.
- *
- * {@hide}
- */
-interface IWifiHotspotManager
-{
-    void test();
-}
-
+parcelable PasspointOsuProvider;
diff --git a/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.java b/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.java
new file mode 100644
index 0000000..80d5315
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.java
@@ -0,0 +1,145 @@
+/*
+ * 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.net.wifi.passpoint;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * TODO: doc
+ */
+public class PasspointOsuProvider implements Parcelable {
+
+    /** TODO: doc */
+    public static final int OSU_METHOD_UNKNOWN = -1;
+
+    /** TODO: doc */
+    public static final int OSU_METHOD_OMADM = 0;
+
+    /** TODO: doc */
+    public static final int OSU_METHOD_SOAP = 1;
+
+    /** TODO: doc */
+    public String ssid;
+
+    /** TODO: doc */
+    public String friendlyName;
+
+    /** TODO: doc */
+    public String serverUri;
+
+    /** TODO: doc */
+    public int osuMethod = OSU_METHOD_UNKNOWN;
+
+    /** TODO: doc */
+    public int iconWidth;
+
+    /** TODO: doc */
+    public int iconHeight;
+
+    /** TODO: doc */
+    public String iconType;
+
+    /** TODO: doc */
+    public String iconFileName;
+
+    /** TODO: doc */
+    public Object icon; // TODO: should change to image format
+
+    /** TODO: doc */
+    public String osuNai;
+
+    /** TODO: doc */
+    public String osuService;
+
+
+    /** default constructor @hide */
+    public PasspointOsuProvider() {
+        // TODO
+    }
+
+    /** copy constructor @hide */
+    public PasspointOsuProvider(PasspointOsuProvider source) {
+        // TODO
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("SSID: ").append(ssid);
+        if (friendlyName != null)
+            sb.append(" friendlyName: ").append(friendlyName);
+        if (serverUri != null)
+            sb.append(" serverUri: ").append(serverUri);
+        sb.append(" osuMethod: ").append(osuMethod);
+        if (iconFileName != null) {
+            sb.append(" icon: [").append(iconWidth).append("x")
+              .append(iconHeight).append(" ")
+              .append(iconType).append(" ")
+              .append(iconFileName);
+        }
+        if (osuNai != null)
+            sb.append(" osuNai: ").append(osuNai);
+        if (osuService != null)
+            sb.append(" osuService: ").append(osuService);
+        return sb.toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeValue(ssid);
+        out.writeValue(friendlyName);
+        out.writeValue(serverUri);
+        out.writeInt(osuMethod);
+        out.writeInt(iconWidth);
+        out.writeInt(iconHeight);
+        out.writeValue(iconType);
+        out.writeValue(iconFileName);
+        out.writeValue(osuNai);
+        out.writeValue(osuService);
+        // TODO: icon image?
+    }
+
+    public static final Parcelable.Creator<PasspointOsuProvider> CREATOR =
+            new Parcelable.Creator<PasspointOsuProvider>() {
+        @Override
+        public PasspointOsuProvider createFromParcel(Parcel in) {
+            PasspointOsuProvider osu = new PasspointOsuProvider();
+            osu.ssid = (String) in.readValue(String.class.getClassLoader());
+            osu.friendlyName = (String) in.readValue(String.class.getClassLoader());
+            osu.serverUri = (String) in.readValue(String.class.getClassLoader());
+            osu.osuMethod = in.readInt();
+            osu.iconWidth = in.readInt();
+            osu.iconHeight = in.readInt();
+            osu.iconType = (String) in.readValue(String.class.getClassLoader());
+            osu.iconFileName = (String) in.readValue(String.class.getClassLoader());
+            osu.osuNai = (String) in.readValue(String.class.getClassLoader());
+            osu.osuService = (String) in.readValue(String.class.getClassLoader());
+            return osu;
+        }
+
+        @Override
+        public PasspointOsuProvider[] newArray(int size) {
+            return new PasspointOsuProvider[size];
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl b/wifi/java/android/net/wifi/passpoint/PasspointPolicy.aidl
similarity index 77%
copy from wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
copy to wifi/java/android/net/wifi/passpoint/PasspointPolicy.aidl
index 2b1601b..c2cc731 100644
--- a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/PasspointPolicy.aidl
@@ -14,15 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.hotspot;
+package android.net.wifi.passpoint;
 
-/**
- * Interface that allows controlling and querying Hotspot connectivity.
- *
- * {@hide}
- */
-interface IWifiHotspotManager
-{
-    void test();
-}
-
+parcelable PasspointPolicy;
diff --git a/wifi/java/android/net/wifi/passpoint/PasspointPolicy.java b/wifi/java/android/net/wifi/passpoint/PasspointPolicy.java
new file mode 100644
index 0000000..3a8806b
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/PasspointPolicy.java
@@ -0,0 +1,55 @@
+/*

+ * 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.net.wifi.passpoint;

+

+import android.os.Parcelable;

+import android.os.Parcel;

+

+public class PasspointPolicy implements Parcelable {

+

+    @Override

+    public String toString() {

+        // TODO

+        return null;

+    }

+

+    /** Implement the Parcelable interface {@hide} */

+    @Override

+    public int describeContents() {

+        return 0;

+    }

+

+    /** Implement the Parcelable interface {@hide} */

+    @Override

+    public void writeToParcel(Parcel dest, int flags) {

+        // TODO

+    }

+

+    /** Implement the Parcelable interface {@hide} */

+    public static final Creator<PasspointPolicy> CREATOR =

+            new Creator<PasspointPolicy>() {

+                @Override

+                public PasspointPolicy createFromParcel(Parcel in) {

+                    return null;

+                }

+

+                @Override

+                public PasspointPolicy[] newArray(int size) {

+                    return new PasspointPolicy[size];

+                }

+            };

+}

diff --git a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl b/wifi/java/android/net/wifi/passpoint/WifiTree.aidl
similarity index 77%
copy from wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
copy to wifi/java/android/net/wifi/passpoint/WifiTree.aidl
index 2b1601b..8e2fab7 100644
--- a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl
+++ b/wifi/java/android/net/wifi/passpoint/WifiTree.aidl
@@ -14,15 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.hotspot;
+package android.net.wifi.passpoint;
 
-/**
- * Interface that allows controlling and querying Hotspot connectivity.
- *
- * {@hide}
- */
-interface IWifiHotspotManager
-{
-    void test();
-}
-
+parcelable WifiTree;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiTree.java b/wifi/java/android/net/wifi/passpoint/WifiTree.java
new file mode 100644
index 0000000..8fdb6e1
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiTree.java
@@ -0,0 +1,51 @@
+/*

+ * 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.net.wifi.passpoint;

+

+import android.os.Parcelable;

+import android.os.Parcel;

+

+/** @hide */

+public class WifiTree implements Parcelable {

+

+    /** Implement the Parcelable interface {@hide} */

+    @Override

+    public int describeContents() {

+        return 0;

+    }

+

+    /** Implement the Parcelable interface {@hide} */

+    @Override

+    public void writeToParcel(Parcel out, int flags) {

+        // TODO

+    }

+

+    /** Implement the Parcelable interface {@hide} */

+    public static final Parcelable.Creator<WifiTree> CREATOR =

+            new Parcelable.Creator<WifiTree>() {

+                @Override

+                public WifiTree createFromParcel(Parcel in) {

+                    // TODO

+                    return null;

+                }

+

+                @Override

+                public WifiTree[] newArray(int size) {

+                    return new WifiTree[size];

+                }

+            };

+}