Merge "Revert "Remove the View#initializeScrollbars API""
diff --git a/Android.mk b/Android.mk
index c80a9ab..5e634c1 100644
--- a/Android.mk
+++ b/Android.mk
@@ -76,8 +76,8 @@
 	core/java/android/app/ISearchManagerCallback.aidl \
 	core/java/android/app/IServiceConnection.aidl \
 	core/java/android/app/IStopUserCallback.aidl \
-        core/java/android/app/task/ITaskCallback.aidl \
-        core/java/android/app/task/ITaskService.aidl \
+	core/java/android/app/task/ITaskCallback.aidl \
+	core/java/android/app/task/ITaskService.aidl \
 	core/java/android/app/IThumbnailRetriever.aidl \
 	core/java/android/app/ITransientNotification.aidl \
 	core/java/android/app/IUiAutomationConnection.aidl \
@@ -320,6 +320,7 @@
 	wifi/java/android/net/wifi/IWifiManager.aidl \
 	wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl \
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
+	wifi/java/android/net/wifi/IWifiScanner.aidl \
 	packages/services/PacProcessor/com/android/net/IProxyService.aidl \
 	packages/services/Proxy/com/android/net/IProxyCallback.aidl \
 	packages/services/Proxy/com/android/net/IProxyPortListener.aidl \
@@ -720,8 +721,9 @@
 $(full_target): $(framework_built) $(gen)
 
 # Run this for checkbuild
-.PHONY: checkbuild
 checkbuild: doc-comment-check-docs
+# Check comment when you are updating the API
+update-api: doc-comment-check-docs
 
 # ====  static html in the sdk ==================================
 include $(CLEAR_VARS)
diff --git a/api/current.txt b/api/current.txt
index 1c9f871..89261b2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -250,7 +250,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 = 16843837; // 0x101043d
+    field public static final int actionBarTheme = 16843831; // 0x1010437
     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 +267,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 = 16843857; // 0x1010451
+    field public static final int actionOverflowMenuStyle = 16843851; // 0x101044b
     field public static final int actionProviderClass = 16843657; // 0x1010389
     field public static final int actionViewClass = 16843516; // 0x10102fc
     field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
@@ -295,7 +295,6 @@
     field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef
     field public static final int alwaysRetainTaskState = 16843267; // 0x1010203
     field public static final int angle = 16843168; // 0x10101a0
-    field public static final int animate = 16843823; // 0x101042f
     field public static final int animateFirstView = 16843477; // 0x10102d5
     field public static final int animateLayoutChanges = 16843506; // 0x10102f2
     field public static final int animateOnClick = 16843356; // 0x101025c
@@ -314,7 +313,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 = 16843859; // 0x1010453
+    field public static final int autoRemoveFromRecents = 16843853; // 0x101044d
     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
@@ -383,29 +382,29 @@
     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 = 16843822; // 0x101042e
+    field public static final int clipToPath = 16843818; // 0x101042a
     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 = 16843842; // 0x1010442
+    field public static final int colorAccent = 16843836; // 0x101043c
     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 = 16843829; // 0x1010435
-    field public static final int colorButtonNormalColored = 16843831; // 0x1010437
-    field public static final int colorButtonPressed = 16843830; // 0x1010436
-    field public static final int colorButtonPressedColored = 16843832; // 0x1010438
-    field public static final int colorControlActivated = 16843828; // 0x1010434
-    field public static final int colorControlNormal = 16843827; // 0x1010433
+    field public static final int colorButtonNormal = 16843823; // 0x101042f
+    field public static final int colorButtonNormalColored = 16843825; // 0x1010431
+    field public static final int colorButtonPressed = 16843824; // 0x1010430
+    field public static final int colorButtonPressedColored = 16843826; // 0x1010432
+    field public static final int colorControlActivated = 16843822; // 0x101042e
+    field public static final int colorControlNormal = 16843821; // 0x101042d
     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 = 16843840; // 0x1010440
-    field public static final int colorPrimaryDark = 16843841; // 0x1010441
-    field public static final int colorPrimaryLight = 16843839; // 0x101043f
+    field public static final int colorPrimary = 16843834; // 0x101043a
+    field public static final int colorPrimaryDark = 16843835; // 0x101043b
+    field public static final int colorPrimaryLight = 16843833; // 0x1010439
     field public static final int columnCount = 16843639; // 0x1010377
     field public static final int columnDelay = 16843215; // 0x10101cf
     field public static final int columnOrderPreserved = 16843640; // 0x1010378
@@ -464,7 +463,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 = 16843858; // 0x1010452
+    field public static final int documentLaunchMode = 16843852; // 0x101044c
     field public static final int drawSelectorOnTop = 16843004; // 0x10100fc
     field public static final int drawable = 16843161; // 0x1010199
     field public static final int drawableBottom = 16843118; // 0x101016e
@@ -487,14 +486,13 @@
     field public static final int dropDownWidth = 16843362; // 0x1010262
     field public static final int duplicateParentState = 16842985; // 0x10100e9
     field public static final int duration = 16843160; // 0x1010198
-    field public static final int durations = 16843814; // 0x1010426
     field public static final int editTextBackground = 16843602; // 0x1010352
     field public static final int editTextColor = 16843601; // 0x1010351
     field public static final int editTextPreferenceStyle = 16842898; // 0x1010092
     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 = 16843853; // 0x101044d
+    field public static final int elevation = 16843847; // 0x1010447
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
     field public static final int enabled = 16842766; // 0x101000e
@@ -504,9 +502,9 @@
     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 = 16843855; // 0x101044f
+    field public static final int excludeClass = 16843849; // 0x1010449
     field public static final int excludeFromRecents = 16842775; // 0x1010017
-    field public static final int excludeId = 16843854; // 0x101044e
+    field public static final int excludeId = 16843848; // 0x1010448
     field public static final int exitFadeDuration = 16843533; // 0x101030d
     field public static final int expandableListPreferredChildIndicatorLeft = 16842834; // 0x1010052
     field public static final int expandableListPreferredChildIndicatorRight = 16842835; // 0x1010053
@@ -535,11 +533,11 @@
     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 = 16843809; // 0x1010421
+    field public static final int fill = 16843808; // 0x1010420
     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 = 16843808; // 0x1010420
+    field public static final int fillOpacity = 16843807; // 0x101041f
     field public static final int fillViewport = 16843130; // 0x101017a
     field public static final int filter = 16843035; // 0x101011b
     field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
@@ -569,6 +567,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 = 16843856; // 0x1010450
     field public static final int fromScene = 16843741; // 0x10103dd
     field public static final int fromXDelta = 16843206; // 0x10101c6
     field public static final int fromXScale = 16843202; // 0x10101c2
@@ -601,7 +600,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 = 16843856; // 0x1010450
+    field public static final int hideOnContentScroll = 16843850; // 0x101044a
     field public static final int hint = 16843088; // 0x1010150
     field public static final int homeAsUpIndicator = 16843531; // 0x101030b
     field public static final int homeLayout = 16843549; // 0x101031d
@@ -771,7 +770,6 @@
     field public static final int layout_x = 16843135; // 0x101017f
     field public static final int layout_y = 16843136; // 0x1010180
     field public static final int left = 16843181; // 0x10101ad
-    field public static final int limitTo = 16843824; // 0x1010430
     field public static final int lineSpacingExtra = 16843287; // 0x1010217
     field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
     field public static final int lines = 16843092; // 0x1010154
@@ -833,7 +831,7 @@
     field public static final int name = 16842755; // 0x1010003
     field public static final int navigationMode = 16843471; // 0x10102cf
     field public static final int negativeButtonText = 16843254; // 0x10101f6
-    field public static final int nestedScrollingEnabled = 16843843; // 0x1010443
+    field public static final int nestedScrollingEnabled = 16843837; // 0x101043d
     field public static final int nextFocusDown = 16842980; // 0x10100e4
     field public static final int nextFocusForward = 16843580; // 0x101033c
     field public static final int nextFocusLeft = 16842977; // 0x10100e1
@@ -875,18 +873,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 = 16843810; // 0x1010422
+    field public static final int pathData = 16843809; // 0x1010421
     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 = 16843833; // 0x1010439
+    field public static final int persistable = 16843827; // 0x1010433
     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 = 16843826; // 0x1010432
+    field public static final int pinned = 16843820; // 0x101042c
     field public static final int pivotX = 16843189; // 0x10101b5
     field public static final int pivotY = 16843190; // 0x10101b6
     field public static final int popupAnimationStyle = 16843465; // 0x10102c9
@@ -941,7 +939,6 @@
     field public static final int readPermission = 16842759; // 0x1010007
     field public static final int repeatCount = 16843199; // 0x10101bf
     field public static final int repeatMode = 16843200; // 0x10101c0
-    field public static final int repeatStyle = 16843816; // 0x1010428
     field public static final int reqFiveWayNav = 16843314; // 0x1010232
     field public static final int reqHardKeyboard = 16843305; // 0x1010229
     field public static final int reqKeyboardType = 16843304; // 0x1010228
@@ -951,7 +948,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 = 16843825; // 0x1010431
+    field public static final int requiredForProfile = 16843819; // 0x101042b
     field public static final int requiresFadingEdge = 16843685; // 0x10103a5
     field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
     field public static final int resizeMode = 16843619; // 0x1010363
@@ -960,6 +957,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 = 16843857; // 0x1010451
     field public static final int right = 16843183; // 0x10101af
     field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093
     field public static final int ringtoneType = 16843257; // 0x10101f9
@@ -1015,8 +1013,7 @@
     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 sequence = 16843815; // 0x1010427
-    field public static final int sessionService = 16843850; // 0x101044a
+    field public static final int sessionService = 16843844; // 0x1010444
     field public static final int settingsActivity = 16843301; // 0x1010225
     field public static final int shadowColor = 16843105; // 0x1010161
     field public static final int shadowDx = 16843106; // 0x1010162
@@ -1038,7 +1035,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 = 16843836; // 0x101043c
+    field public static final int slideEdge = 16843830; // 0x1010436
     field public static final int smallIcon = 16843422; // 0x101029e
     field public static final int smallScreens = 16843396; // 0x1010284
     field public static final int smoothScrollbar = 16843313; // 0x1010231
@@ -1055,12 +1052,13 @@
     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 = 16843851; // 0x101044b
+    field public static final int stackViewStyle = 16843845; // 0x1010445
     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 = 16843854; // 0x101044e
     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
@@ -1090,13 +1088,13 @@
     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 = 16843811; // 0x1010423
-    field public static final int strokeLineCap = 16843820; // 0x101042c
-    field public static final int strokeLineJoin = 16843821; // 0x101042d
-    field public static final int strokeOpacity = 16843812; // 0x1010424
-    field public static final int strokeWidth = 16843813; // 0x1010425
+    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 subtitle = 16843473; // 0x10102d1
-    field public static final int subtitleTextAppearance = 16843835; // 0x101043b
+    field public static final int subtitleTextAppearance = 16843829; // 0x1010435
     field public static final int subtitleTextStyle = 16843513; // 0x10102f9
     field public static final int subtypeExtraValue = 16843674; // 0x101039a
     field public static final int subtypeId = 16843713; // 0x10103c1
@@ -1113,7 +1111,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 = 16843852; // 0x101044c
+    field public static final int switchStyle = 16843846; // 0x1010446
     field public static final int switchTextAppearance = 16843630; // 0x101036e
     field public static final int switchTextOff = 16843628; // 0x101036c
     field public static final int switchTextOn = 16843627; // 0x101036b
@@ -1150,7 +1148,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 = 16843838; // 0x101043e
+    field public static final int textAppearanceListItemSecondary = 16843832; // 0x1010438
     field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
     field public static final int textAppearanceMedium = 16842817; // 0x1010041
     field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
@@ -1214,10 +1212,11 @@
     field public static final int tintMode = 16843798; // 0x1010416
     field public static final int title = 16843233; // 0x10101e1
     field public static final int titleCondensed = 16843234; // 0x10101e2
-    field public static final int titleTextAppearance = 16843834; // 0x101043a
+    field public static final int titleTextAppearance = 16843828; // 0x1010434
     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 = 16843855; // 0x101044f
     field public static final int toScene = 16843742; // 0x10103de
     field public static final int toXDelta = 16843207; // 0x10101c7
     field public static final int toXScale = 16843203; // 0x10101c3
@@ -1239,10 +1238,9 @@
     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 trigger = 16843805; // 0x101041d
-    field public static final int trimPathEnd = 16843818; // 0x101042a
-    field public static final int trimPathOffset = 16843819; // 0x101042b
-    field public static final int trimPathStart = 16843817; // 0x1010429
+    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 type = 16843169; // 0x10101a1
     field public static final int typeface = 16842902; // 0x1010096
     field public static final int uiOptions = 16843672; // 0x1010398
@@ -1267,8 +1265,8 @@
     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 viewportHeight = 16843807; // 0x101041f
-    field public static final int viewportWidth = 16843806; // 0x101041e
+    field public static final int viewportHeight = 16843806; // 0x101041e
+    field public static final int viewportWidth = 16843805; // 0x101041d
     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,8 +1295,8 @@
     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 = 16843849; // 0x1010449
-    field public static final int windowAllowExitTransitionOverlap = 16843848; // 0x1010448
+    field public static final int windowAllowEnterTransitionOverlap = 16843843; // 0x1010443
+    field public static final int windowAllowExitTransitionOverlap = 16843842; // 0x1010442
     field public static final int windowAnimationStyle = 16842926; // 0x10100ae
     field public static final int windowBackground = 16842836; // 0x1010054
     field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
@@ -1308,9 +1306,9 @@
     field public static final int windowDisablePreview = 16843298; // 0x1010222
     field public static final int windowEnableSplitTouch = 16843543; // 0x1010317
     field public static final int windowEnterAnimation = 16842932; // 0x10100b4
-    field public static final int windowEnterTransition = 16843844; // 0x1010444
+    field public static final int windowEnterTransition = 16843838; // 0x101043e
     field public static final int windowExitAnimation = 16842933; // 0x10100b5
-    field public static final int windowExitTransition = 16843845; // 0x1010445
+    field public static final int windowExitTransition = 16843839; // 0x101043f
     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 +1319,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 = 16843846; // 0x1010446
-    field public static final int windowSharedElementExitTransition = 16843847; // 0x1010447
+    field public static final int windowSharedElementEnterTransition = 16843840; // 0x1010440
+    field public static final int windowSharedElementExitTransition = 16843841; // 0x1010441
     field public static final int windowShowAnimation = 16842934; // 0x10100b6
     field public static final int windowShowWallpaper = 16843410; // 0x1010292
     field public static final int windowSoftInputMode = 16843307; // 0x101022b
@@ -2788,6 +2786,7 @@
   public class AnimatorInflater {
     ctor public AnimatorInflater();
     method public static android.animation.Animator loadAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
+    method public static android.animation.StateListAnimator loadStateListAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
   }
 
   public abstract class AnimatorListenerAdapter implements android.animation.Animator.AnimatorListener android.animation.Animator.AnimatorPauseListener {
@@ -2984,6 +2983,12 @@
     method public android.graphics.Rect evaluate(float, android.graphics.Rect, android.graphics.Rect);
   }
 
+  public class StateListAnimator {
+    ctor public StateListAnimator();
+    method public void addState(int[], android.animation.Animator);
+    method public void jumpToCurrentState();
+  }
+
   public class TimeAnimator extends android.animation.ValueAnimator {
     ctor public TimeAnimator();
     method public void setTimeListener(android.animation.TimeAnimator.TimeListener);
@@ -3256,6 +3261,7 @@
     method public boolean onContextItemSelected(android.view.MenuItem);
     method public void onContextMenuClosed(android.view.Menu);
     method protected void onCreate(android.os.Bundle);
+    method protected void onCreate(android.os.Bundle, android.os.PersistableBundle);
     method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
     method public java.lang.CharSequence onCreateDescription();
     method protected deprecated android.app.Dialog onCreateDialog(int);
@@ -3286,6 +3292,7 @@
     method public void onPanelClosed(int, android.view.Menu);
     method protected void onPause();
     method protected void onPostCreate(android.os.Bundle);
+    method protected void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
     method protected void onPostResume();
     method protected deprecated void onPrepareDialog(int, android.app.Dialog);
     method protected deprecated void onPrepareDialog(int, android.app.Dialog, android.os.Bundle);
@@ -3295,9 +3302,11 @@
     method public void onProvideAssistData(android.os.Bundle);
     method protected void onRestart();
     method protected void onRestoreInstanceState(android.os.Bundle);
+    method protected void onRestoreInstanceState(android.os.Bundle, android.os.PersistableBundle);
     method protected void onResume();
     method public deprecated java.lang.Object onRetainNonConfigurationInstance();
     method protected void onSaveInstanceState(android.os.Bundle);
+    method protected void onSaveInstanceState(android.os.Bundle, android.os.PersistableBundle);
     method public boolean onSearchRequested();
     method protected void onStart();
     method protected void onStop();
@@ -3363,10 +3372,12 @@
     method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
     method public void startIntentSenderFromChild(android.app.Activity, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+    method public void startLockTask();
     method public deprecated void startManagingCursor(android.database.Cursor);
     method public boolean startNextMatchingActivity(android.content.Intent);
     method public boolean startNextMatchingActivity(android.content.Intent, android.os.Bundle);
     method public void startSearch(java.lang.String, boolean, android.os.Bundle, boolean);
+    method public void stopLockTask();
     method public deprecated void stopManagingCursor(android.database.Cursor);
     method public void takeKeyEvents(boolean);
     method public void triggerSearch(java.lang.String, android.os.Bundle);
@@ -4191,14 +4202,18 @@
     method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
     method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
     method public void callActivityOnCreate(android.app.Activity, android.os.Bundle);
+    method public void callActivityOnCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
     method public void callActivityOnDestroy(android.app.Activity);
     method public void callActivityOnNewIntent(android.app.Activity, android.content.Intent);
     method public void callActivityOnPause(android.app.Activity);
     method public void callActivityOnPostCreate(android.app.Activity, android.os.Bundle);
+    method public void callActivityOnPostCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
     method public void callActivityOnRestart(android.app.Activity);
     method public void callActivityOnRestoreInstanceState(android.app.Activity, android.os.Bundle);
+    method public void callActivityOnRestoreInstanceState(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
     method public void callActivityOnResume(android.app.Activity);
     method public void callActivityOnSaveInstanceState(android.app.Activity, android.os.Bundle);
+    method public void callActivityOnSaveInstanceState(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
     method public void callActivityOnStart(android.app.Activity);
     method public void callActivityOnStop(android.app.Activity);
     method public void callActivityOnUserLeaving(android.app.Activity);
@@ -4428,6 +4443,7 @@
     field public static final java.lang.String CATEGORY_STATUS = "status";
     field public static final java.lang.String CATEGORY_SYSTEM = "sys";
     field public static final java.lang.String CATEGORY_TRANSPORT = "transport";
+    field public static final int COLOR_DEFAULT = 0; // 0x0
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int DEFAULT_ALL = -1; // 0xffffffff
     field public static final int DEFAULT_LIGHTS = 4; // 0x4
@@ -4473,6 +4489,7 @@
     field public int audioStreamType;
     field public android.widget.RemoteViews bigContentView;
     field public java.lang.String category;
+    field public int color;
     field public android.app.PendingIntent contentIntent;
     field public android.widget.RemoteViews contentView;
     field public int defaults;
@@ -4535,6 +4552,7 @@
     method public deprecated android.app.Notification getNotification();
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setCategory(java.lang.String);
+    method public android.app.Notification.Builder setColor(int);
     method public android.app.Notification.Builder setContent(android.widget.RemoteViews);
     method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
     method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
@@ -5017,6 +5035,7 @@
     method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
     method public void enableSystemApp(android.content.ComponentName, java.lang.String);
     method public int enableSystemApp(android.content.ComponentName, android.content.Intent);
+    method public java.lang.String[] getAccountTypesWithManagementDisabled();
     method public java.util.List<android.content.ComponentName> getActiveAdmins();
     method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
     method public boolean getCameraDisabled(android.content.ComponentName);
@@ -5042,13 +5061,16 @@
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isDeviceOwnerApp(java.lang.String);
+    method public boolean isLockTaskPermitted(android.content.ComponentName);
     method public boolean isProfileOwnerApp(java.lang.String);
     method public void lockNow();
     method public void removeActiveAdmin(android.content.ComponentName);
     method public boolean resetPassword(java.lang.String, int);
+    method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
+    method public void setLockTaskComponents(android.content.ComponentName[]) throws java.lang.SecurityException;
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
@@ -8038,6 +8060,7 @@
     field public static final java.lang.String FEATURE_CAMERA = "android.hardware.camera";
     field public static final java.lang.String FEATURE_CAMERA_ANY = "android.hardware.camera.any";
     field public static final java.lang.String FEATURE_CAMERA_AUTOFOCUS = "android.hardware.camera.autofocus";
+    field public static final java.lang.String FEATURE_CAMERA_EXTERNAL = "android.hardware.camera.external";
     field public static final java.lang.String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash";
     field public static final java.lang.String FEATURE_CAMERA_FRONT = "android.hardware.camera.front";
     field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
@@ -8063,6 +8086,7 @@
     field public static final java.lang.String FEATURE_SENSOR_BAROMETER = "android.hardware.sensor.barometer";
     field public static final java.lang.String FEATURE_SENSOR_COMPASS = "android.hardware.sensor.compass";
     field public static final java.lang.String FEATURE_SENSOR_GYROSCOPE = "android.hardware.sensor.gyroscope";
+    field public static final java.lang.String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate";
     field public static final java.lang.String FEATURE_SENSOR_LIGHT = "android.hardware.sensor.light";
     field public static final java.lang.String FEATURE_SENSOR_PROXIMITY = "android.hardware.sensor.proximity";
     field public static final java.lang.String FEATURE_SENSOR_STEP_COUNTER = "android.hardware.sensor.stepcounter";
@@ -10809,6 +10833,12 @@
     method public abstract void stop();
   }
 
+  public class AnimatedStateListDrawable extends android.graphics.drawable.StateListDrawable {
+    ctor public AnimatedStateListDrawable();
+    method public void addState(int[], android.graphics.drawable.Drawable, int);
+    method public void addTransition(int, int, android.graphics.drawable.AnimationDrawable, boolean);
+  }
+
   public class AnimationDrawable extends android.graphics.drawable.DrawableContainer implements android.graphics.drawable.Animatable java.lang.Runnable {
     ctor public AnimationDrawable();
     method public void addFrame(android.graphics.drawable.Drawable, int);
@@ -11851,7 +11881,6 @@
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_INFO_WHITE_LEVEL;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_MAX_ANALOG_SENSITIVITY;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_ORIENTATION;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_REFERENCE_ILLUMINANT1;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_REFERENCE_ILLUMINANT2;
     field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES;
@@ -12233,8 +12262,6 @@
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_GREEN_SPLIT;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_NEUTRAL_COLOR_POINT;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP;
-    field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_TONE_CURVE;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_SENSITIVITY;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEMPERATURE;
     field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_DATA;
@@ -12860,6 +12887,7 @@
     method public void onStartInputView(android.view.inputmethod.EditorInfo, boolean);
     method public void onUnbindInput();
     method public void onUpdateCursor(android.graphics.Rect);
+    method public void onUpdateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
     method public void onUpdateExtractedText(int, android.view.inputmethod.ExtractedText);
     method public void onUpdateExtractingViews(android.view.inputmethod.EditorInfo);
     method public void onUpdateExtractingVisibility(android.view.inputmethod.EditorInfo);
@@ -12909,6 +12937,7 @@
     method public void finishInput();
     method public void toggleSoftInput(int, int);
     method public void updateCursor(android.graphics.Rect);
+    method public void updateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
     method public void updateExtractedText(int, android.view.inputmethod.ExtractedText);
     method public void updateSelection(int, int, int, int, int, int);
     method public void viewClicked(boolean);
@@ -13354,6 +13383,7 @@
     field public static final int ENCODING_INVALID = 0; // 0x0
     field public static final int ENCODING_PCM_16BIT = 2; // 0x2
     field public static final int ENCODING_PCM_8BIT = 3; // 0x3
+    field public static final int ENCODING_PCM_FLOAT = 4; // 0x4
   }
 
   public class AudioManager {
@@ -13571,6 +13601,8 @@
     method public void stop() throws java.lang.IllegalStateException;
     method public int write(byte[], int, int);
     method public int write(short[], int, int);
+    method public int write(float[], int, int, int);
+    method public int write(java.nio.ByteBuffer, int, int);
     field public static final int ERROR = -1; // 0xffffffff
     field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
     field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
@@ -13583,6 +13615,8 @@
     field public static final int STATE_NO_STATIC_DATA = 2; // 0x2
     field public static final int STATE_UNINITIALIZED = 0; // 0x0
     field public static final int SUCCESS = 0; // 0x0
+    field public static final int WRITE_BLOCKING = 0; // 0x0
+    field public static final int WRITE_NON_BLOCKING = 1; // 0x1
   }
 
   public static abstract interface AudioTrack.OnPlaybackPositionUpdateListener {
@@ -13800,6 +13834,7 @@
     method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
     method public final void release();
     method public final void releaseOutputBuffer(int, boolean);
+    method public final void releaseOutputBuffer(int, long);
     method public void setNotificationCallback(android.media.MediaCodec.NotificationCallback);
     method public final void setParameters(android.os.Bundle);
     method public final void setVideoScalingMode(int);
@@ -15712,6 +15747,7 @@
     method public android.net.NetworkInfo getActiveNetworkInfo();
     method public android.net.NetworkInfo[] getAllNetworkInfo();
     method public deprecated boolean getBackgroundDataSetting();
+    method public android.net.ProxyInfo getGlobalProxy();
     method public android.net.NetworkInfo getNetworkInfo(int);
     method public int getNetworkPreference();
     method public boolean isActiveNetworkMetered();
@@ -15719,6 +15755,7 @@
     method public static boolean isNetworkTypeValid(int);
     method public void registerNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
     method public boolean requestRouteToHost(int, int);
+    method public void setGlobalProxy(android.net.ProxyInfo);
     method public void setNetworkPreference(int);
     method public int startUsingNetworkFeature(int, java.lang.String);
     method public int stopUsingNetworkFeature(int, java.lang.String);
@@ -15894,9 +15931,22 @@
     method public static final deprecated int getDefaultPort();
     method public static final deprecated java.lang.String getHost(android.content.Context);
     method public static final deprecated int getPort(android.content.Context);
+    field public static final java.lang.String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
     field public static final java.lang.String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
   }
 
+  public class ProxyInfo implements android.os.Parcelable {
+    method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int);
+    method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int, java.util.List<java.lang.String>);
+    method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
+    method public int describeContents();
+    method public java.lang.String[] getExclusionList();
+    method public java.lang.String getHost();
+    method public android.net.Uri getPacFileUrl();
+    method public int getPort();
+    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;
@@ -17108,6 +17158,7 @@
   }
 
   public final class CardEmulation {
+    method public boolean categoryAllowsForegroundPreference(java.lang.String);
     method public android.nfc.cardemulation.AidGroup getAidGroupForService(android.content.ComponentName, java.lang.String);
     method public static synchronized android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter);
     method public int getSelectionModeForCategory(java.lang.String);
@@ -17115,6 +17166,8 @@
     method public boolean isDefaultServiceForCategory(android.content.ComponentName, java.lang.String);
     method public boolean registerAidGroupForService(android.content.ComponentName, android.nfc.cardemulation.AidGroup);
     method public boolean removeAidGroupForService(android.content.ComponentName, java.lang.String);
+    method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
+    method public boolean unsetPreferredService(android.app.Activity);
     field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
     field public static final java.lang.String CATEGORY_OTHER = "other";
     field public static final java.lang.String CATEGORY_PAYMENT = "payment";
@@ -20521,6 +20574,7 @@
     method public void setUserRestrictions(android.os.Bundle);
     method public void setUserRestrictions(android.os.Bundle, android.os.UserHandle);
     field public static final java.lang.String DISALLOW_ADD_USER = "no_add_user";
+    field public static final java.lang.String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
     field public static final java.lang.String DISALLOW_CONFIG_APPS = "no_config_apps";
     field public static final java.lang.String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
     field public static final java.lang.String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
@@ -20534,9 +20588,11 @@
     field public static final java.lang.String DISALLOW_INSTALL_APPS = "no_install_apps";
     field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
     field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
+    field public static final java.lang.String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
     field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
     field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
     field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
+    field public static final java.lang.String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
     field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
     field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
   }
@@ -24561,6 +24617,7 @@
     method public void contextDump();
     method public static android.renderscript.RenderScript create(android.content.Context);
     method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType);
+    method public static android.renderscript.RenderScript create(android.content.Context, android.renderscript.RenderScript.ContextType, long);
     method public void destroy();
     method public void finish();
     method public final android.content.Context getApplicationContext();
@@ -24570,6 +24627,9 @@
     method public void setErrorHandler(android.renderscript.RenderScript.RSErrorHandler);
     method public void setMessageHandler(android.renderscript.RenderScript.RSMessageHandler);
     method public void setPriority(android.renderscript.RenderScript.Priority);
+    field public static final long CREATE_FLAG_LOW_LATENCY = 1L; // 0x1L
+    field public static final long CREATE_FLAG_LOW_POWER = 2L; // 0x2L
+    field public static final long CREATE_FLAG_NONE = 0L; // 0x0L
   }
 
   public static final class RenderScript.ContextType extends java.lang.Enum {
@@ -25684,6 +25744,636 @@
 
 }
 
+package android.system {
+
+  public final class ErrnoException extends java.lang.Exception {
+    ctor public ErrnoException(java.lang.String, int);
+    ctor public ErrnoException(java.lang.String, int, java.lang.Throwable);
+    field public final int errno;
+  }
+
+  public final class Os {
+    method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
+    method public static boolean access(java.lang.String, int) throws android.system.ErrnoException;
+    method public static void bind(java.io.FileDescriptor, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
+    method public static void chmod(java.lang.String, int) throws android.system.ErrnoException;
+    method public static void chown(java.lang.String, int, int) throws android.system.ErrnoException;
+    method public static void close(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static void connect(java.io.FileDescriptor, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
+    method public static java.io.FileDescriptor dup(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static java.io.FileDescriptor dup2(java.io.FileDescriptor, int) throws android.system.ErrnoException;
+    method public static java.lang.String[] environ();
+    method public static void execv(java.lang.String, java.lang.String[]) throws android.system.ErrnoException;
+    method public static void execve(java.lang.String, java.lang.String[], java.lang.String[]) throws android.system.ErrnoException;
+    method public static void fchmod(java.io.FileDescriptor, int) throws android.system.ErrnoException;
+    method public static void fchown(java.io.FileDescriptor, int, int) throws android.system.ErrnoException;
+    method public static void fdatasync(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static android.system.StructStat fstat(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static android.system.StructStatVfs fstatvfs(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static void fsync(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static void ftruncate(java.io.FileDescriptor, long) throws android.system.ErrnoException;
+    method public static java.lang.String gai_strerror(int);
+    method public static int getegid();
+    method public static java.lang.String getenv(java.lang.String);
+    method public static int geteuid();
+    method public static int getgid();
+    method public static java.net.SocketAddress getpeername(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static int getpid();
+    method public static int getppid();
+    method public static java.net.SocketAddress getsockname(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static int gettid();
+    method public static int getuid();
+    method public static java.lang.String if_indextoname(int);
+    method public static java.net.InetAddress inet_pton(int, java.lang.String);
+    method public static boolean isatty(java.io.FileDescriptor);
+    method public static void kill(int, int) throws android.system.ErrnoException;
+    method public static void lchown(java.lang.String, int, int) throws android.system.ErrnoException;
+    method public static void listen(java.io.FileDescriptor, int) throws android.system.ErrnoException;
+    method public static long lseek(java.io.FileDescriptor, long, int) throws android.system.ErrnoException;
+    method public static android.system.StructStat lstat(java.lang.String) throws android.system.ErrnoException;
+    method public static void mincore(long, long, byte[]) throws android.system.ErrnoException;
+    method public static void mkdir(java.lang.String, int) throws android.system.ErrnoException;
+    method public static void mkfifo(java.lang.String, int) throws android.system.ErrnoException;
+    method public static void mlock(long, long) throws android.system.ErrnoException;
+    method public static long mmap(long, long, int, int, java.io.FileDescriptor, long) throws android.system.ErrnoException;
+    method public static void msync(long, long, int) throws android.system.ErrnoException;
+    method public static void munlock(long, long) throws android.system.ErrnoException;
+    method public static void munmap(long, long) throws android.system.ErrnoException;
+    method public static java.io.FileDescriptor open(java.lang.String, int, int) throws android.system.ErrnoException;
+    method public static java.io.FileDescriptor[] pipe() throws android.system.ErrnoException;
+    method public static int poll(android.system.StructPollfd[], int) throws android.system.ErrnoException;
+    method public static void posix_fallocate(java.io.FileDescriptor, long, long) throws android.system.ErrnoException;
+    method public static int prctl(int, long, long, long, long) throws android.system.ErrnoException;
+    method public static int pread(java.io.FileDescriptor, java.nio.ByteBuffer, long) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int pread(java.io.FileDescriptor, byte[], int, int, long) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int pwrite(java.io.FileDescriptor, java.nio.ByteBuffer, long) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int pwrite(java.io.FileDescriptor, byte[], int, int, long) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int read(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int read(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static java.lang.String readlink(java.lang.String) throws android.system.ErrnoException;
+    method public static int readv(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int recvfrom(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
+    method public static int recvfrom(java.io.FileDescriptor, byte[], int, int, int, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
+    method public static void remove(java.lang.String) throws android.system.ErrnoException;
+    method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
+    method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+    method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
+    method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
+    method public static void setegid(int) throws android.system.ErrnoException;
+    method public static void setenv(java.lang.String, java.lang.String, boolean) throws android.system.ErrnoException;
+    method public static void seteuid(int) throws android.system.ErrnoException;
+    method public static void setgid(int) throws android.system.ErrnoException;
+    method public static int setsid() throws android.system.ErrnoException;
+    method public static void setuid(int) throws android.system.ErrnoException;
+    method public static void shutdown(java.io.FileDescriptor, int) throws android.system.ErrnoException;
+    method public static java.io.FileDescriptor socket(int, int, int) throws android.system.ErrnoException;
+    method public static void socketpair(int, int, int, java.io.FileDescriptor, java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static android.system.StructStat stat(java.lang.String) throws android.system.ErrnoException;
+    method public static android.system.StructStatVfs statvfs(java.lang.String) throws android.system.ErrnoException;
+    method public static java.lang.String strerror(int);
+    method public static java.lang.String strsignal(int);
+    method public static void symlink(java.lang.String, java.lang.String) throws android.system.ErrnoException;
+    method public static long sysconf(int);
+    method public static void tcdrain(java.io.FileDescriptor) throws android.system.ErrnoException;
+    method public static void tcsendbreak(java.io.FileDescriptor, int) throws android.system.ErrnoException;
+    method public static int umask(int);
+    method public static android.system.StructUtsname uname();
+    method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
+    method public static int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+    method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
+    method public static int writev(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
+  }
+
+  public final class OsConstants {
+    method public static boolean S_ISBLK(int);
+    method public static boolean S_ISCHR(int);
+    method public static boolean S_ISDIR(int);
+    method public static boolean S_ISFIFO(int);
+    method public static boolean S_ISLNK(int);
+    method public static boolean S_ISREG(int);
+    method public static boolean S_ISSOCK(int);
+    method public static boolean WCOREDUMP(int);
+    method public static int WEXITSTATUS(int);
+    method public static boolean WIFEXITED(int);
+    method public static boolean WIFSIGNALED(int);
+    method public static boolean WIFSTOPPED(int);
+    method public static int WSTOPSIG(int);
+    method public static int WTERMSIG(int);
+    method public static java.lang.String errnoName(int);
+    method public static java.lang.String gaiName(int);
+    field public static final int AF_INET;
+    field public static final int AF_INET6;
+    field public static final int AF_UNIX;
+    field public static final int AF_UNSPEC;
+    field public static final int AI_ADDRCONFIG;
+    field public static final int AI_ALL;
+    field public static final int AI_CANONNAME;
+    field public static final int AI_NUMERICHOST;
+    field public static final int AI_NUMERICSERV;
+    field public static final int AI_PASSIVE;
+    field public static final int AI_V4MAPPED;
+    field public static final int CAP_AUDIT_CONTROL;
+    field public static final int CAP_AUDIT_WRITE;
+    field public static final int CAP_BLOCK_SUSPEND;
+    field public static final int CAP_CHOWN;
+    field public static final int CAP_DAC_OVERRIDE;
+    field public static final int CAP_DAC_READ_SEARCH;
+    field public static final int CAP_FOWNER;
+    field public static final int CAP_FSETID;
+    field public static final int CAP_IPC_LOCK;
+    field public static final int CAP_IPC_OWNER;
+    field public static final int CAP_KILL;
+    field public static final int CAP_LAST_CAP;
+    field public static final int CAP_LEASE;
+    field public static final int CAP_LINUX_IMMUTABLE;
+    field public static final int CAP_MAC_ADMIN;
+    field public static final int CAP_MAC_OVERRIDE;
+    field public static final int CAP_MKNOD;
+    field public static final int CAP_NET_ADMIN;
+    field public static final int CAP_NET_BIND_SERVICE;
+    field public static final int CAP_NET_BROADCAST;
+    field public static final int CAP_NET_RAW;
+    field public static final int CAP_SETFCAP;
+    field public static final int CAP_SETGID;
+    field public static final int CAP_SETPCAP;
+    field public static final int CAP_SETUID;
+    field public static final int CAP_SYSLOG;
+    field public static final int CAP_SYS_ADMIN;
+    field public static final int CAP_SYS_BOOT;
+    field public static final int CAP_SYS_CHROOT;
+    field public static final int CAP_SYS_MODULE;
+    field public static final int CAP_SYS_NICE;
+    field public static final int CAP_SYS_PACCT;
+    field public static final int CAP_SYS_PTRACE;
+    field public static final int CAP_SYS_RAWIO;
+    field public static final int CAP_SYS_RESOURCE;
+    field public static final int CAP_SYS_TIME;
+    field public static final int CAP_SYS_TTY_CONFIG;
+    field public static final int CAP_WAKE_ALARM;
+    field public static final int E2BIG;
+    field public static final int EACCES;
+    field public static final int EADDRINUSE;
+    field public static final int EADDRNOTAVAIL;
+    field public static final int EAFNOSUPPORT;
+    field public static final int EAGAIN;
+    field public static final int EAI_AGAIN;
+    field public static final int EAI_BADFLAGS;
+    field public static final int EAI_FAIL;
+    field public static final int EAI_FAMILY;
+    field public static final int EAI_MEMORY;
+    field public static final int EAI_NODATA;
+    field public static final int EAI_NONAME;
+    field public static final int EAI_OVERFLOW;
+    field public static final int EAI_SERVICE;
+    field public static final int EAI_SOCKTYPE;
+    field public static final int EAI_SYSTEM;
+    field public static final int EALREADY;
+    field public static final int EBADF;
+    field public static final int EBADMSG;
+    field public static final int EBUSY;
+    field public static final int ECANCELED;
+    field public static final int ECHILD;
+    field public static final int ECONNABORTED;
+    field public static final int ECONNREFUSED;
+    field public static final int ECONNRESET;
+    field public static final int EDEADLK;
+    field public static final int EDESTADDRREQ;
+    field public static final int EDOM;
+    field public static final int EDQUOT;
+    field public static final int EEXIST;
+    field public static final int EFAULT;
+    field public static final int EFBIG;
+    field public static final int EHOSTUNREACH;
+    field public static final int EIDRM;
+    field public static final int EILSEQ;
+    field public static final int EINPROGRESS;
+    field public static final int EINTR;
+    field public static final int EINVAL;
+    field public static final int EIO;
+    field public static final int EISCONN;
+    field public static final int EISDIR;
+    field public static final int ELOOP;
+    field public static final int EMFILE;
+    field public static final int EMLINK;
+    field public static final int EMSGSIZE;
+    field public static final int EMULTIHOP;
+    field public static final int ENAMETOOLONG;
+    field public static final int ENETDOWN;
+    field public static final int ENETRESET;
+    field public static final int ENETUNREACH;
+    field public static final int ENFILE;
+    field public static final int ENOBUFS;
+    field public static final int ENODATA;
+    field public static final int ENODEV;
+    field public static final int ENOENT;
+    field public static final int ENOEXEC;
+    field public static final int ENOLCK;
+    field public static final int ENOLINK;
+    field public static final int ENOMEM;
+    field public static final int ENOMSG;
+    field public static final int ENOPROTOOPT;
+    field public static final int ENOSPC;
+    field public static final int ENOSR;
+    field public static final int ENOSTR;
+    field public static final int ENOSYS;
+    field public static final int ENOTCONN;
+    field public static final int ENOTDIR;
+    field public static final int ENOTEMPTY;
+    field public static final int ENOTSOCK;
+    field public static final int ENOTSUP;
+    field public static final int ENOTTY;
+    field public static final int ENXIO;
+    field public static final int EOPNOTSUPP;
+    field public static final int EOVERFLOW;
+    field public static final int EPERM;
+    field public static final int EPIPE;
+    field public static final int EPROTO;
+    field public static final int EPROTONOSUPPORT;
+    field public static final int EPROTOTYPE;
+    field public static final int ERANGE;
+    field public static final int EROFS;
+    field public static final int ESPIPE;
+    field public static final int ESRCH;
+    field public static final int ESTALE;
+    field public static final int ETIME;
+    field public static final int ETIMEDOUT;
+    field public static final int ETXTBSY;
+    field public static final int EXDEV;
+    field public static final int EXIT_FAILURE;
+    field public static final int EXIT_SUCCESS;
+    field public static final int FD_CLOEXEC;
+    field public static final int FIONREAD;
+    field public static final int F_DUPFD;
+    field public static final int F_GETFD;
+    field public static final int F_GETFL;
+    field public static final int F_GETLK;
+    field public static final int F_GETLK64;
+    field public static final int F_GETOWN;
+    field public static final int F_OK;
+    field public static final int F_RDLCK;
+    field public static final int F_SETFD;
+    field public static final int F_SETFL;
+    field public static final int F_SETLK;
+    field public static final int F_SETLK64;
+    field public static final int F_SETLKW;
+    field public static final int F_SETLKW64;
+    field public static final int F_SETOWN;
+    field public static final int F_UNLCK;
+    field public static final int F_WRLCK;
+    field public static final int IFA_F_DADFAILED;
+    field public static final int IFA_F_DEPRECATED;
+    field public static final int IFA_F_HOMEADDRESS;
+    field public static final int IFA_F_NODAD;
+    field public static final int IFA_F_OPTIMISTIC;
+    field public static final int IFA_F_PERMANENT;
+    field public static final int IFA_F_SECONDARY;
+    field public static final int IFA_F_TEMPORARY;
+    field public static final int IFA_F_TENTATIVE;
+    field public static final int IFF_ALLMULTI;
+    field public static final int IFF_AUTOMEDIA;
+    field public static final int IFF_BROADCAST;
+    field public static final int IFF_DEBUG;
+    field public static final int IFF_DYNAMIC;
+    field public static final int IFF_LOOPBACK;
+    field public static final int IFF_MASTER;
+    field public static final int IFF_MULTICAST;
+    field public static final int IFF_NOARP;
+    field public static final int IFF_NOTRAILERS;
+    field public static final int IFF_POINTOPOINT;
+    field public static final int IFF_PORTSEL;
+    field public static final int IFF_PROMISC;
+    field public static final int IFF_RUNNING;
+    field public static final int IFF_SLAVE;
+    field public static final int IFF_UP;
+    field public static final int IPPROTO_ICMP;
+    field public static final int IPPROTO_ICMPV6;
+    field public static final int IPPROTO_IP;
+    field public static final int IPPROTO_IPV6;
+    field public static final int IPPROTO_RAW;
+    field public static final int IPPROTO_TCP;
+    field public static final int IPPROTO_UDP;
+    field public static final int IPV6_CHECKSUM;
+    field public static final int IPV6_MULTICAST_HOPS;
+    field public static final int IPV6_MULTICAST_IF;
+    field public static final int IPV6_MULTICAST_LOOP;
+    field public static final int IPV6_RECVDSTOPTS;
+    field public static final int IPV6_RECVHOPLIMIT;
+    field public static final int IPV6_RECVHOPOPTS;
+    field public static final int IPV6_RECVPKTINFO;
+    field public static final int IPV6_RECVRTHDR;
+    field public static final int IPV6_RECVTCLASS;
+    field public static final int IPV6_TCLASS;
+    field public static final int IPV6_UNICAST_HOPS;
+    field public static final int IPV6_V6ONLY;
+    field public static final int IP_MULTICAST_IF;
+    field public static final int IP_MULTICAST_LOOP;
+    field public static final int IP_MULTICAST_TTL;
+    field public static final int IP_TOS;
+    field public static final int IP_TTL;
+    field public static final int MAP_FIXED;
+    field public static final int MAP_PRIVATE;
+    field public static final int MAP_SHARED;
+    field public static final int MCAST_BLOCK_SOURCE;
+    field public static final int MCAST_JOIN_GROUP;
+    field public static final int MCAST_JOIN_SOURCE_GROUP;
+    field public static final int MCAST_LEAVE_GROUP;
+    field public static final int MCAST_LEAVE_SOURCE_GROUP;
+    field public static final int MCAST_UNBLOCK_SOURCE;
+    field public static final int MCL_CURRENT;
+    field public static final int MCL_FUTURE;
+    field public static final int MSG_CTRUNC;
+    field public static final int MSG_DONTROUTE;
+    field public static final int MSG_EOR;
+    field public static final int MSG_OOB;
+    field public static final int MSG_PEEK;
+    field public static final int MSG_TRUNC;
+    field public static final int MSG_WAITALL;
+    field public static final int MS_ASYNC;
+    field public static final int MS_INVALIDATE;
+    field public static final int MS_SYNC;
+    field public static final int NI_DGRAM;
+    field public static final int NI_NAMEREQD;
+    field public static final int NI_NOFQDN;
+    field public static final int NI_NUMERICHOST;
+    field public static final int NI_NUMERICSERV;
+    field public static final int O_ACCMODE;
+    field public static final int O_APPEND;
+    field public static final int O_CREAT;
+    field public static final int O_EXCL;
+    field public static final int O_NOCTTY;
+    field public static final int O_NOFOLLOW;
+    field public static final int O_NONBLOCK;
+    field public static final int O_RDONLY;
+    field public static final int O_RDWR;
+    field public static final int O_SYNC;
+    field public static final int O_TRUNC;
+    field public static final int O_WRONLY;
+    field public static final int POLLERR;
+    field public static final int POLLHUP;
+    field public static final int POLLIN;
+    field public static final int POLLNVAL;
+    field public static final int POLLOUT;
+    field public static final int POLLPRI;
+    field public static final int POLLRDBAND;
+    field public static final int POLLRDNORM;
+    field public static final int POLLWRBAND;
+    field public static final int POLLWRNORM;
+    field public static final int PROT_EXEC;
+    field public static final int PROT_NONE;
+    field public static final int PROT_READ;
+    field public static final int PROT_WRITE;
+    field public static final int PR_SET_NO_NEW_PRIVS;
+    field public static final int RT_SCOPE_HOST;
+    field public static final int RT_SCOPE_LINK;
+    field public static final int RT_SCOPE_NOWHERE;
+    field public static final int RT_SCOPE_SITE;
+    field public static final int RT_SCOPE_UNIVERSE;
+    field public static final int R_OK;
+    field public static final int SEEK_CUR;
+    field public static final int SEEK_END;
+    field public static final int SEEK_SET;
+    field public static final int SHUT_RD;
+    field public static final int SHUT_RDWR;
+    field public static final int SHUT_WR;
+    field public static final int SIGABRT;
+    field public static final int SIGALRM;
+    field public static final int SIGBUS;
+    field public static final int SIGCHLD;
+    field public static final int SIGCONT;
+    field public static final int SIGFPE;
+    field public static final int SIGHUP;
+    field public static final int SIGILL;
+    field public static final int SIGINT;
+    field public static final int SIGIO;
+    field public static final int SIGKILL;
+    field public static final int SIGPIPE;
+    field public static final int SIGPROF;
+    field public static final int SIGPWR;
+    field public static final int SIGQUIT;
+    field public static final int SIGRTMAX;
+    field public static final int SIGRTMIN;
+    field public static final int SIGSEGV;
+    field public static final int SIGSTKFLT;
+    field public static final int SIGSTOP;
+    field public static final int SIGSYS;
+    field public static final int SIGTERM;
+    field public static final int SIGTRAP;
+    field public static final int SIGTSTP;
+    field public static final int SIGTTIN;
+    field public static final int SIGTTOU;
+    field public static final int SIGURG;
+    field public static final int SIGUSR1;
+    field public static final int SIGUSR2;
+    field public static final int SIGVTALRM;
+    field public static final int SIGWINCH;
+    field public static final int SIGXCPU;
+    field public static final int SIGXFSZ;
+    field public static final int SIOCGIFADDR;
+    field public static final int SIOCGIFBRDADDR;
+    field public static final int SIOCGIFDSTADDR;
+    field public static final int SIOCGIFNETMASK;
+    field public static final int SOCK_DGRAM;
+    field public static final int SOCK_RAW;
+    field public static final int SOCK_SEQPACKET;
+    field public static final int SOCK_STREAM;
+    field public static final int SOL_SOCKET;
+    field public static final int SO_BINDTODEVICE;
+    field public static final int SO_BROADCAST;
+    field public static final int SO_DEBUG;
+    field public static final int SO_DONTROUTE;
+    field public static final int SO_ERROR;
+    field public static final int SO_KEEPALIVE;
+    field public static final int SO_LINGER;
+    field public static final int SO_OOBINLINE;
+    field public static final int SO_PASSCRED;
+    field public static final int SO_PEERCRED;
+    field public static final int SO_RCVBUF;
+    field public static final int SO_RCVLOWAT;
+    field public static final int SO_RCVTIMEO;
+    field public static final int SO_REUSEADDR;
+    field public static final int SO_SNDBUF;
+    field public static final int SO_SNDLOWAT;
+    field public static final int SO_SNDTIMEO;
+    field public static final int SO_TYPE;
+    field public static final int STDERR_FILENO;
+    field public static final int STDIN_FILENO;
+    field public static final int STDOUT_FILENO;
+    field public static final int S_IFBLK;
+    field public static final int S_IFCHR;
+    field public static final int S_IFDIR;
+    field public static final int S_IFIFO;
+    field public static final int S_IFLNK;
+    field public static final int S_IFMT;
+    field public static final int S_IFREG;
+    field public static final int S_IFSOCK;
+    field public static final int S_IRGRP;
+    field public static final int S_IROTH;
+    field public static final int S_IRUSR;
+    field public static final int S_IRWXG;
+    field public static final int S_IRWXO;
+    field public static final int S_IRWXU;
+    field public static final int S_ISGID;
+    field public static final int S_ISUID;
+    field public static final int S_ISVTX;
+    field public static final int S_IWGRP;
+    field public static final int S_IWOTH;
+    field public static final int S_IWUSR;
+    field public static final int S_IXGRP;
+    field public static final int S_IXOTH;
+    field public static final int S_IXUSR;
+    field public static final int TCP_NODELAY;
+    field public static final int WCONTINUED;
+    field public static final int WEXITED;
+    field public static final int WNOHANG;
+    field public static final int WNOWAIT;
+    field public static final int WSTOPPED;
+    field public static final int WUNTRACED;
+    field public static final int W_OK;
+    field public static final int X_OK;
+    field public static final int _SC_2_CHAR_TERM;
+    field public static final int _SC_2_C_BIND;
+    field public static final int _SC_2_C_DEV;
+    field public static final int _SC_2_C_VERSION;
+    field public static final int _SC_2_FORT_DEV;
+    field public static final int _SC_2_FORT_RUN;
+    field public static final int _SC_2_LOCALEDEF;
+    field public static final int _SC_2_SW_DEV;
+    field public static final int _SC_2_UPE;
+    field public static final int _SC_2_VERSION;
+    field public static final int _SC_AIO_LISTIO_MAX;
+    field public static final int _SC_AIO_MAX;
+    field public static final int _SC_AIO_PRIO_DELTA_MAX;
+    field public static final int _SC_ARG_MAX;
+    field public static final int _SC_ASYNCHRONOUS_IO;
+    field public static final int _SC_ATEXIT_MAX;
+    field public static final int _SC_AVPHYS_PAGES;
+    field public static final int _SC_BC_BASE_MAX;
+    field public static final int _SC_BC_DIM_MAX;
+    field public static final int _SC_BC_SCALE_MAX;
+    field public static final int _SC_BC_STRING_MAX;
+    field public static final int _SC_CHILD_MAX;
+    field public static final int _SC_CLK_TCK;
+    field public static final int _SC_COLL_WEIGHTS_MAX;
+    field public static final int _SC_DELAYTIMER_MAX;
+    field public static final int _SC_EXPR_NEST_MAX;
+    field public static final int _SC_FSYNC;
+    field public static final int _SC_GETGR_R_SIZE_MAX;
+    field public static final int _SC_GETPW_R_SIZE_MAX;
+    field public static final int _SC_IOV_MAX;
+    field public static final int _SC_JOB_CONTROL;
+    field public static final int _SC_LINE_MAX;
+    field public static final int _SC_LOGIN_NAME_MAX;
+    field public static final int _SC_MAPPED_FILES;
+    field public static final int _SC_MEMLOCK;
+    field public static final int _SC_MEMLOCK_RANGE;
+    field public static final int _SC_MEMORY_PROTECTION;
+    field public static final int _SC_MESSAGE_PASSING;
+    field public static final int _SC_MQ_OPEN_MAX;
+    field public static final int _SC_MQ_PRIO_MAX;
+    field public static final int _SC_NGROUPS_MAX;
+    field public static final int _SC_NPROCESSORS_CONF;
+    field public static final int _SC_NPROCESSORS_ONLN;
+    field public static final int _SC_OPEN_MAX;
+    field public static final int _SC_PAGESIZE;
+    field public static final int _SC_PAGE_SIZE;
+    field public static final int _SC_PASS_MAX;
+    field public static final int _SC_PHYS_PAGES;
+    field public static final int _SC_PRIORITIZED_IO;
+    field public static final int _SC_PRIORITY_SCHEDULING;
+    field public static final int _SC_REALTIME_SIGNALS;
+    field public static final int _SC_RE_DUP_MAX;
+    field public static final int _SC_RTSIG_MAX;
+    field public static final int _SC_SAVED_IDS;
+    field public static final int _SC_SEMAPHORES;
+    field public static final int _SC_SEM_NSEMS_MAX;
+    field public static final int _SC_SEM_VALUE_MAX;
+    field public static final int _SC_SHARED_MEMORY_OBJECTS;
+    field public static final int _SC_SIGQUEUE_MAX;
+    field public static final int _SC_STREAM_MAX;
+    field public static final int _SC_SYNCHRONIZED_IO;
+    field public static final int _SC_THREADS;
+    field public static final int _SC_THREAD_ATTR_STACKADDR;
+    field public static final int _SC_THREAD_ATTR_STACKSIZE;
+    field public static final int _SC_THREAD_DESTRUCTOR_ITERATIONS;
+    field public static final int _SC_THREAD_KEYS_MAX;
+    field public static final int _SC_THREAD_PRIORITY_SCHEDULING;
+    field public static final int _SC_THREAD_PRIO_INHERIT;
+    field public static final int _SC_THREAD_PRIO_PROTECT;
+    field public static final int _SC_THREAD_SAFE_FUNCTIONS;
+    field public static final int _SC_THREAD_STACK_MIN;
+    field public static final int _SC_THREAD_THREADS_MAX;
+    field public static final int _SC_TIMERS;
+    field public static final int _SC_TIMER_MAX;
+    field public static final int _SC_TTY_NAME_MAX;
+    field public static final int _SC_TZNAME_MAX;
+    field public static final int _SC_VERSION;
+    field public static final int _SC_XBS5_ILP32_OFF32;
+    field public static final int _SC_XBS5_ILP32_OFFBIG;
+    field public static final int _SC_XBS5_LP64_OFF64;
+    field public static final int _SC_XBS5_LPBIG_OFFBIG;
+    field public static final int _SC_XOPEN_CRYPT;
+    field public static final int _SC_XOPEN_ENH_I18N;
+    field public static final int _SC_XOPEN_LEGACY;
+    field public static final int _SC_XOPEN_REALTIME;
+    field public static final int _SC_XOPEN_REALTIME_THREADS;
+    field public static final int _SC_XOPEN_SHM;
+    field public static final int _SC_XOPEN_UNIX;
+    field public static final int _SC_XOPEN_VERSION;
+    field public static final int _SC_XOPEN_XCU_VERSION;
+  }
+
+  public final class StructPollfd {
+    ctor public StructPollfd();
+    field public short events;
+    field public java.io.FileDescriptor fd;
+    field public short revents;
+    field public java.lang.Object userData;
+  }
+
+  public final class StructStat {
+    ctor public StructStat(long, long, int, long, int, int, long, long, long, long, long, long, long);
+    field public final long st_atime;
+    field public final long st_blksize;
+    field public final long st_blocks;
+    field public final long st_ctime;
+    field public final long st_dev;
+    field public final int st_gid;
+    field public final long st_ino;
+    field public final int st_mode;
+    field public final long st_mtime;
+    field public final long st_nlink;
+    field public final long st_rdev;
+    field public final long st_size;
+    field public final int st_uid;
+  }
+
+  public final class StructStatVfs {
+    ctor public StructStatVfs(long, long, long, long, long, long, long, long, long, long, long);
+    field public final long f_bavail;
+    field public final long f_bfree;
+    field public final long f_blocks;
+    field public final long f_bsize;
+    field public final long f_favail;
+    field public final long f_ffree;
+    field public final long f_files;
+    field public final long f_flag;
+    field public final long f_frsize;
+    field public final long f_fsid;
+    field public final long f_namemax;
+  }
+
+  public final class StructUtsname {
+    ctor public StructUtsname(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    field public final java.lang.String machine;
+    field public final java.lang.String nodename;
+    field public final java.lang.String release;
+    field public final java.lang.String sysname;
+    field public final java.lang.String version;
+  }
+
+}
+
 package android.telephony {
 
   public final class CellIdentityCdma implements android.os.Parcelable {
@@ -28843,6 +29533,46 @@
     method public void previousMonth();
   }
 
+  public final class MutableBoolean {
+    ctor public MutableBoolean(boolean);
+    field public boolean value;
+  }
+
+  public final class MutableByte {
+    ctor public MutableByte(byte);
+    field public byte value;
+  }
+
+  public final class MutableChar {
+    ctor public MutableChar(char);
+    field public char value;
+  }
+
+  public final class MutableDouble {
+    ctor public MutableDouble(double);
+    field public double value;
+  }
+
+  public final class MutableFloat {
+    ctor public MutableFloat(float);
+    field public float value;
+  }
+
+  public final class MutableInt {
+    ctor public MutableInt(int);
+    field public int value;
+  }
+
+  public final class MutableLong {
+    ctor public MutableLong(long);
+    field public long value;
+  }
+
+  public final class MutableShort {
+    ctor public MutableShort(short);
+    field public short value;
+  }
+
   public class NoSuchPropertyException extends java.lang.RuntimeException {
     ctor public NoSuchPropertyException(java.lang.String);
   }
@@ -30530,6 +31260,7 @@
     method public final int getScrollY();
     method public java.lang.String getSharedElementName();
     method public int getSolidColor();
+    method public android.animation.StateListAnimator getStateListAnimator();
     method protected int getSuggestedMinimumHeight();
     method protected int getSuggestedMinimumWidth();
     method public int getSystemUiVisibility();
@@ -30794,6 +31525,7 @@
     method public void setSelected(boolean);
     method public void setSharedElementName(java.lang.String);
     method public void setSoundEffectsEnabled(boolean);
+    method public void setStateListAnimator(android.animation.StateListAnimator);
     method public void setSystemUiVisibility(int);
     method public void setTag(java.lang.Object);
     method public void setTag(int, java.lang.Object);
@@ -32514,6 +33246,34 @@
     field public static final android.os.Parcelable.Creator CREATOR;
   }
 
+  public final class CursorAnchorInfo implements android.os.Parcelable {
+    ctor public CursorAnchorInfo(android.os.Parcel);
+    method public int describeContents();
+    method public int getCandidatesEnd();
+    method public int getCandidatesStart();
+    method public android.graphics.RectF getCharacterRect(int);
+    method public float getInsertionMarkerBaseline();
+    method public float getInsertionMarkerBottom();
+    method public float getInsertionMarkerHorizontal();
+    method public float getInsertionMarkerTop();
+    method public android.graphics.Matrix getMatrix();
+    method public int getSelectionEnd();
+    method public int getSelectionStart();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static final class CursorAnchorInfo.CursorAnchorInfoBuilder {
+    ctor public CursorAnchorInfo.CursorAnchorInfoBuilder();
+    method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder addCharacterRect(int, float, float, float, float);
+    method public android.view.inputmethod.CursorAnchorInfo build();
+    method public void reset();
+    method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setCandidateRange(int, int);
+    method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setInsertionMarkerLocation(float, float, float, float);
+    method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setMatrix(android.graphics.Matrix);
+    method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setSelectionRange(int, int);
+  }
+
   public class EditorInfo implements android.text.InputType android.os.Parcelable {
     ctor public EditorInfo();
     method public int describeContents();
@@ -32722,6 +33482,7 @@
     method public void toggleSoftInput(int, int);
     method public void toggleSoftInputFromWindow(android.os.IBinder, int, int);
     method public void updateCursor(android.view.View, int, int, int, int);
+    method public void updateCursorAnchorInfo(android.view.View, android.view.inputmethod.CursorAnchorInfo);
     method public void updateExtractedText(android.view.View, int, android.view.inputmethod.ExtractedText);
     method public void updateSelection(android.view.View, int, int, int, int);
     method public void viewClicked(android.view.View);
@@ -32744,6 +33505,7 @@
     method public abstract void finishInput();
     method public abstract void toggleSoftInput(int, int);
     method public abstract void updateCursor(android.graphics.Rect);
+    method public abstract void updateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo);
     method public abstract void updateExtractedText(int, android.view.inputmethod.ExtractedText);
     method public abstract void updateSelection(int, int, int, int, int, int);
     method public abstract void viewClicked(boolean);
@@ -32993,7 +33755,6 @@
     method public abstract long getResources();
     method public abstract void grant(long);
     field public static final long RESOURCE_AUDIO_CAPTURE = 4L; // 0x4L
-    field public static final long RESOURCE_GEOLOCATION = 1L; // 0x1L
     field public static final long RESOURCE_VIDEO_CAPTURE = 2L; // 0x2L
   }
 
@@ -39798,11 +40559,13 @@
     method public java.lang.String getValue();
     method public int getVersion();
     method public boolean hasExpired();
+    method public boolean isHttpOnly();
     method public static java.util.List<java.net.HttpCookie> parse(java.lang.String);
     method public void setComment(java.lang.String);
     method public void setCommentURL(java.lang.String);
     method public void setDiscard(boolean);
     method public void setDomain(java.lang.String);
+    method public void setHttpOnly(boolean);
     method public void setMaxAge(long);
     method public void setPath(java.lang.String);
     method public void setPortlist(java.lang.String);
@@ -40755,7 +41518,7 @@
     ctor public ConnectionPendingException();
   }
 
-  public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel {
+  public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.MulticastChannel java.nio.channels.ScatteringByteChannel {
     ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider);
     method public java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException;
     method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException;
@@ -40763,6 +41526,8 @@
     method public java.net.SocketAddress getLocalAddress() throws java.io.IOException;
     method public T getOption(java.net.SocketOption<T>) throws java.io.IOException;
     method public abstract boolean isConnected();
+    method public java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
+    method public java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
     method public static java.nio.channels.DatagramChannel open() throws java.io.IOException;
     method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException;
     method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException;
@@ -40810,6 +41575,7 @@
 
   public abstract class FileLock implements java.lang.AutoCloseable {
     ctor protected FileLock(java.nio.channels.FileChannel, long, long, boolean);
+    method public java.nio.channels.Channel acquiredBy();
     method public final java.nio.channels.FileChannel channel();
     method public final void close() throws java.io.IOException;
     method public final boolean isShared();
@@ -40842,6 +41608,24 @@
     method public abstract void close() throws java.io.IOException;
   }
 
+  public abstract class MembershipKey {
+    ctor protected MembershipKey();
+    method public abstract java.nio.channels.MembershipKey block(java.net.InetAddress) throws java.io.IOException;
+    method public abstract java.nio.channels.MulticastChannel channel();
+    method public abstract void drop();
+    method public abstract java.net.InetAddress group();
+    method public abstract boolean isValid();
+    method public abstract java.net.NetworkInterface networkInterface();
+    method public abstract java.net.InetAddress sourceAddress();
+    method public abstract java.nio.channels.MembershipKey unblock(java.net.InetAddress);
+  }
+
+  public abstract interface MulticastChannel implements java.nio.channels.NetworkChannel {
+    method public abstract void close() throws java.io.IOException;
+    method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException;
+    method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException;
+  }
+
   public abstract interface NetworkChannel implements java.lang.AutoCloseable java.nio.channels.Channel java.io.Closeable {
     method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException;
     method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException;
@@ -44947,6 +45731,7 @@
     method public java.lang.String getDisplayName(java.util.Locale);
     method public static java.util.Currency getInstance(java.lang.String);
     method public static java.util.Currency getInstance(java.util.Locale);
+    method public int getNumericCode();
     method public java.lang.String getSymbol();
     method public java.lang.String getSymbol(java.util.Locale);
   }
@@ -48029,8 +48814,10 @@
 
   public class ZipFile implements java.io.Closeable {
     ctor public ZipFile(java.io.File) throws java.io.IOException, java.util.zip.ZipException;
+    ctor public ZipFile(java.io.File, java.nio.charset.Charset) throws java.io.IOException, java.util.zip.ZipException;
     ctor public ZipFile(java.lang.String) throws java.io.IOException;
     ctor public ZipFile(java.io.File, int) throws java.io.IOException;
+    ctor public ZipFile(java.io.File, int, java.nio.charset.Charset) throws java.io.IOException;
     method public void close() throws java.io.IOException;
     method public java.util.Enumeration<? extends java.util.zip.ZipEntry> entries();
     method public java.lang.String getComment();
@@ -48084,6 +48871,7 @@
 
   public class ZipInputStream extends java.util.zip.InflaterInputStream {
     ctor public ZipInputStream(java.io.InputStream);
+    ctor public ZipInputStream(java.io.InputStream, java.nio.charset.Charset);
     method public void closeEntry() throws java.io.IOException;
     method protected java.util.zip.ZipEntry createZipEntry(java.lang.String);
     method public java.util.zip.ZipEntry getNextEntry() throws java.io.IOException;
@@ -48131,6 +48919,7 @@
 
   public class ZipOutputStream extends java.util.zip.DeflaterOutputStream {
     ctor public ZipOutputStream(java.io.OutputStream);
+    ctor public ZipOutputStream(java.io.OutputStream, java.nio.charset.Charset);
     method public void closeEntry() throws java.io.IOException;
     method public void putNextEntry(java.util.zip.ZipEntry) throws java.io.IOException;
     method public void setComment(java.lang.String);
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 20236aa..933135d 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -21,6 +21,7 @@
 import android.content.res.XmlResourceParser;
 import android.content.res.Resources.NotFoundException;
 import android.util.AttributeSet;
+import android.util.StateSet;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.animation.AnimationUtils;
@@ -87,9 +88,86 @@
         }
     }
 
+    public static StateListAnimator loadStateListAnimator(Context context, int id)
+            throws NotFoundException {
+        XmlResourceParser parser = null;
+        try {
+            parser = context.getResources().getAnimation(id);
+            return createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
+        } catch (XmlPullParserException ex) {
+            Resources.NotFoundException rnf =
+                    new Resources.NotFoundException(
+                            "Can't load state list animator resource ID #0x" +
+                                    Integer.toHexString(id)
+                    );
+            rnf.initCause(ex);
+            throw rnf;
+        } catch (IOException ex) {
+            Resources.NotFoundException rnf =
+                    new Resources.NotFoundException(
+                            "Can't load state list animator resource ID #0x" +
+                                    Integer.toHexString(id)
+                    );
+            rnf.initCause(ex);
+            throw rnf;
+        } finally {
+            if (parser != null) {
+                parser.close();
+            }
+        }
+    }
+
+    private static StateListAnimator createStateListAnimatorFromXml(Context context,
+            XmlPullParser parser, AttributeSet attributeSet)
+            throws IOException, XmlPullParserException {
+        int type;
+        StateListAnimator stateListAnimator = new StateListAnimator();
+
+        while (true) {
+            type = parser.next();
+            switch (type) {
+                case XmlPullParser.END_DOCUMENT:
+                case XmlPullParser.END_TAG:
+                    return stateListAnimator;
+
+                case XmlPullParser.START_TAG:
+                    // parse item
+                    Animator animator = null;
+                    if ("item".equals(parser.getName())) {
+                        int attributeCount = parser.getAttributeCount();
+                        int[] states = new int[attributeCount];
+                        int stateIndex = 0;
+                        for (int i = 0; i < attributeCount; i++) {
+                            int attrName = attributeSet.getAttributeNameResource(i);
+                            if (attrName == com.android.internal.R.attr.animation) {
+                                animator = loadAnimator(context,
+                                        attributeSet.getAttributeResourceValue(i, 0));
+                            } else {
+                                states[stateIndex++] =
+                                        attributeSet.getAttributeBooleanValue(i, false) ?
+                                                attrName : -attrName;
+                            }
+
+                        }
+                        if (animator == null) {
+                            animator = createAnimatorFromXml(context, parser);
+                        }
+
+                        if (animator == null) {
+                            throw new Resources.NotFoundException(
+                                    "animation state item must have a valid animation");
+                        }
+                        stateListAnimator
+                                .addState(StateSet.trimStateSet(states, stateIndex), animator);
+
+                    }
+                    break;
+            }
+        }
+    }
+
     private static Animator createAnimatorFromXml(Context c, XmlPullParser parser)
             throws XmlPullParserException, IOException {
-
         return createAnimatorFromXml(c, parser, Xml.asAttributeSet(parser), null, 0);
     }
 
diff --git a/core/java/android/animation/StateListAnimator.java b/core/java/android/animation/StateListAnimator.java
new file mode 100644
index 0000000..bc4843d
--- /dev/null
+++ b/core/java/android/animation/StateListAnimator.java
@@ -0,0 +1,209 @@
+/*
+ * 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.animation;
+
+import android.util.StateSet;
+import android.view.View;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+/**
+ * Lets you define a number of Animators that will run on the attached View depending on the View's
+ * drawable state.
+ * <p>
+ * It can be defined in an XML file with the <code>&lt;selector></code> element.
+ * Each State Animator is defined in a nested <code>&lt;item></code> element.
+ *
+ * @attr ref android.R.styleable#DrawableStates_state_focused
+ * @attr ref android.R.styleable#DrawableStates_state_window_focused
+ * @attr ref android.R.styleable#DrawableStates_state_enabled
+ * @attr ref android.R.styleable#DrawableStates_state_checkable
+ * @attr ref android.R.styleable#DrawableStates_state_checked
+ * @attr ref android.R.styleable#DrawableStates_state_selected
+ * @attr ref android.R.styleable#DrawableStates_state_activated
+ * @attr ref android.R.styleable#DrawableStates_state_active
+ * @attr ref android.R.styleable#DrawableStates_state_single
+ * @attr ref android.R.styleable#DrawableStates_state_first
+ * @attr ref android.R.styleable#DrawableStates_state_middle
+ * @attr ref android.R.styleable#DrawableStates_state_last
+ * @attr ref android.R.styleable#DrawableStates_state_pressed
+ * @attr ref android.R.styleable#StateListAnimatorItem_animation
+ */
+public class StateListAnimator {
+
+    private final ArrayList<Tuple> mTuples = new ArrayList<Tuple>();
+
+    private Tuple mLastMatch = null;
+
+    private Animator mRunningAnimator = null;
+
+    private WeakReference<View> mViewRef;
+
+    private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (mRunningAnimator == animation) {
+                mRunningAnimator = null;
+            }
+        }
+    };
+
+    /**
+     * Associates the given animator with the provided drawable state specs so that it will be run
+     * when the View's drawable state matches the specs.
+     *
+     * @param specs The drawable state specs to match against
+     * @param animator The animator to run when the specs match
+     */
+    public void addState(int[] specs, Animator animator) {
+        Tuple tuple = new Tuple(specs, animator);
+        tuple.mAnimator.addListener(mAnimatorListener);
+        mTuples.add(tuple);
+    }
+
+    /**
+     * Returns the current {@link android.animation.Animator} which is started because of a state
+     * change.
+     *
+     * @return The currently running Animator or null if no Animator is running
+     * @hide
+     */
+    public Animator getRunningAnimator() {
+        return mRunningAnimator;
+    }
+
+    /**
+     * @hide
+     */
+    public View getTarget() {
+        return mViewRef == null ? null : mViewRef.get();
+    }
+
+    /**
+     * Called by View
+     * @hide
+     */
+    public void setTarget(View view) {
+        final View current = getTarget();
+        if (current == view) {
+            return;
+        }
+        if (current != null) {
+            clearTarget();
+        }
+        if (view != null) {
+            mViewRef = new WeakReference<View>(view);
+        }
+
+    }
+
+    private void clearTarget() {
+        final int size = mTuples.size();
+        for (int i = 0; i < size; i++) {
+            mTuples.get(i).mAnimator.setTarget(null);
+        }
+
+        mViewRef = null;
+        mLastMatch = null;
+        mRunningAnimator = null;
+    }
+
+    /**
+     * Called by View
+     * @hide
+     */
+    public void setState(int[] state) {
+        Tuple match = null;
+        final int count = mTuples.size();
+        for (int i = 0; i < count; i++) {
+            final Tuple tuple = mTuples.get(i);
+            if (StateSet.stateSetMatches(tuple.mSpecs, state)) {
+                match = tuple;
+                break;
+            }
+        }
+        if (match == mLastMatch) {
+            return;
+        }
+        if (mLastMatch != null) {
+            cancel(mLastMatch);
+        }
+        mLastMatch = match;
+        if (match != null) {
+            start(match);
+        }
+    }
+
+    private void start(Tuple match) {
+        match.mAnimator.setTarget(getTarget());
+        mRunningAnimator = match.mAnimator;
+        match.mAnimator.start();
+    }
+
+    private void cancel(Tuple lastMatch) {
+        lastMatch.mAnimator.cancel();
+        lastMatch.mAnimator.setTarget(null);
+    }
+
+    /**
+     * @hide
+     */
+    public ArrayList<Tuple> getTuples() {
+        return mTuples;
+    }
+
+    /**
+     * If there is an animation running for a recent state change, ends it.
+     * <p>
+     * This causes the animation to assign the end value(s) to the View.
+     */
+    public void jumpToCurrentState() {
+        if (mRunningAnimator != null) {
+            mRunningAnimator.end();
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public static class Tuple {
+
+        final int[] mSpecs;
+
+        final Animator mAnimator;
+
+        private Tuple(int[] specs, Animator animator) {
+            mSpecs = specs;
+            mAnimator = animator;
+        }
+
+        /**
+         * @hide
+         */
+        public int[] getSpecs() {
+            return mSpecs;
+        }
+
+        /**
+         * @hide
+         */
+        public Animator getAnimator() {
+            return mAnimator;
+        }
+    }
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index af3a92c..b4b3c99 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.annotation.NonNull;
+import android.os.PersistableBundle;
 import android.transition.Scene;
 import android.transition.TransitionManager;
 import android.util.ArrayMap;
@@ -29,6 +30,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.app.admin.DevicePolicyManager;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -921,6 +923,30 @@
     }
 
     /**
+     * Same as {@link #onCreate(android.os.Bundle)} but called for those activities created with
+     * the attribute {@link android.R.attr#persistable} set true.
+     *
+     * @param savedInstanceState if the activity is being re-initialized after
+     *     previously being shut down then this Bundle contains the data it most
+     *     recently supplied in {@link #onSaveInstanceState}.
+     *     <b><i>Note: Otherwise it is null.</i></b>
+     * @param persistentState if the activity is being re-initialized after
+     *     previously being shut down or powered off then this Bundle contains the data it most
+     *     recently supplied to outPersistentState in {@link #onSaveInstanceState}.
+     *     <b><i>Note: Otherwise it is null.</i></b>
+     *
+     * @see #onCreate(android.os.Bundle)
+     * @see #onStart
+     * @see #onSaveInstanceState
+     * @see #onRestoreInstanceState
+     * @see #onPostCreate
+     */
+    protected void onCreate(@Nullable Bundle savedInstanceState,
+            @Nullable PersistableBundle persistentState) {
+        onCreate(savedInstanceState);
+    }
+
+    /**
      * The hook for {@link ActivityThread} to restore the state of this activity.
      *
      * Calls {@link #onSaveInstanceState(android.os.Bundle)} and
@@ -934,6 +960,23 @@
     }
 
     /**
+     * The hook for {@link ActivityThread} to restore the state of this activity.
+     *
+     * Calls {@link #onSaveInstanceState(android.os.Bundle)} and
+     * {@link #restoreManagedDialogs(android.os.Bundle)}.
+     *
+     * @param savedInstanceState contains the saved state
+     * @param persistentState contains the persistable saved state
+     */
+    final void performRestoreInstanceState(Bundle savedInstanceState,
+            PersistableBundle persistentState) {
+        onRestoreInstanceState(savedInstanceState, persistentState);
+        if (savedInstanceState != null) {
+            restoreManagedDialogs(savedInstanceState);
+        }
+    }
+
+    /**
      * This method is called after {@link #onStart} when the activity is
      * being re-initialized from a previously saved state, given here in
      * <var>savedInstanceState</var>.  Most implementations will simply use {@link #onCreate}
@@ -961,7 +1004,34 @@
             }
         }
     }
-    
+
+    /**
+     * This is the same as {@link #onRestoreInstanceState(Bundle)} but is called for activities
+     * created with the attribute {@link android.R.attr#persistable}. The {@link
+     * android.os.PersistableBundle} passed came from the restored PersistableBundle first
+     * saved in {@link #onSaveInstanceState(Bundle, PersistableBundle)}.
+     *
+     * <p>This method is called between {@link #onStart} and
+     * {@link #onPostCreate}.
+     *
+     * <p>If this method is called {@link #onRestoreInstanceState(Bundle)} will not be called.
+     *
+     * @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
+     * @param persistentState the data most recently supplied in {@link #onSaveInstanceState}.
+     *
+     * @see #onRestoreInstanceState(Bundle)
+     * @see #onCreate
+     * @see #onPostCreate
+     * @see #onResume
+     * @see #onSaveInstanceState
+     */
+    protected void onRestoreInstanceState(Bundle savedInstanceState,
+            PersistableBundle persistentState) {
+        if (savedInstanceState != null) {
+            onRestoreInstanceState(savedInstanceState);
+        }
+    }
+
     /**
      * Restore the state of any saved managed dialogs.
      *
@@ -1038,6 +1108,21 @@
     }
 
     /**
+     * This is the same as {@link #onPostCreate(Bundle)} but is called for activities
+     * created with the attribute {@link android.R.attr#persistable}.
+     *
+     * @param savedInstanceState The data most recently supplied in {@link #onSaveInstanceState}
+     * @param persistentState The data caming from the PersistableBundle first
+     * saved in {@link #onSaveInstanceState(Bundle, PersistableBundle)}.
+     *
+     * @see #onCreate
+     */
+    protected void onPostCreate(@Nullable Bundle savedInstanceState,
+            @Nullable PersistableBundle persistentState) {
+        onPostCreate(savedInstanceState);
+    }
+
+    /**
      * Called after {@link #onCreate} &mdash; or after {@link #onRestart} when  
      * the activity had been stopped, but is now again being displayed to the 
      * user.  It will be followed by {@link #onResume}.
@@ -1193,6 +1278,22 @@
     }
 
     /**
+     * The hook for {@link ActivityThread} to save the state of this activity.
+     *
+     * Calls {@link #onSaveInstanceState(android.os.Bundle)}
+     * and {@link #saveManagedDialogs(android.os.Bundle)}.
+     *
+     * @param outState The bundle to save the state to.
+     * @param outPersistentState The bundle to save persistent state to.
+     */
+    final void performSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
+        onSaveInstanceState(outState, outPersistentState);
+        saveManagedDialogs(outState);
+        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState +
+                ", " + outPersistentState);
+    }
+
+    /**
      * Called to retrieve per-instance state from an activity before being killed
      * so that the state can be restored in {@link #onCreate} or
      * {@link #onRestoreInstanceState} (the {@link Bundle} populated by this method
@@ -1247,6 +1348,25 @@
     }
 
     /**
+     * This is the same as {@link #onSaveInstanceState} but is called for activities
+     * created with the attribute {@link android.R.attr#persistable}. The {@link
+     * android.os.PersistableBundle} passed in will be saved and presented in
+     * {@link #onCreate(Bundle, PersistableBundle)} the first time that this activity
+     * is restarted following the next device reboot.
+     *
+     * @param outState Bundle in which to place your saved state.
+     * @param outPersistentState State which will be saved across reboots.
+     *
+     * @see #onSaveInstanceState(Bundle)
+     * @see #onCreate
+     * @see #onRestoreInstanceState(Bundle, PersistableBundle)
+     * @see #onPause
+     */
+    protected void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
+        onSaveInstanceState(outState);
+    }
+
+    /**
      * Save the state of any managed dialogs.
      *
      * @param outState place to store the saved state.
@@ -3498,13 +3618,15 @@
         }
 
         // Get the primary color and update the RecentsActivityValues for this activity
-        TypedArray a = getTheme().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);
+        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);
+            }
         }
     }
 
@@ -4806,6 +4928,7 @@
     public void setRecentsActivityValues(ActivityManager.RecentsActivityValues values) {
         ActivityManager.RecentsActivityValues activityValues =
                 new ActivityManager.RecentsActivityValues(values);
+        // Scale the icon down to something reasonable
         if (values.icon != null) {
             final int size = ActivityManager.getLauncherLargeIconSizeInner(this);
             activityValues.icon = Bitmap.createScaledBitmap(values.icon, size, size, true);
@@ -5487,13 +5610,22 @@
         return mParent != null ? mParent.getActivityToken() : mToken;
     }
 
-    final void performCreate(Bundle icicle) {
-        onCreate(icicle);
+    final void performCreateCommon() {
         mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
                 com.android.internal.R.styleable.Window_windowNoDisplay, false);
         mFragments.dispatchActivityCreated();
     }
 
+    final void performCreate(Bundle icicle) {
+        onCreate(icicle);
+        performCreateCommon();
+    }
+
+    final void performCreate(Bundle icicle, PersistableBundle persistentState) {
+        onCreate(icicle, persistentState);
+        performCreateCommon();
+    }
+
     final void performStart() {
         mFragments.noteStateNotSaved();
         mCalled = false;
@@ -5689,7 +5821,16 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Put this Activity in a mode where the user is locked to the
+     * current task.
+     *
+     * This will prevent the user from launching other apps, going to settings,
+     * or reaching the home screen.
+     *
+     * Lock task mode will only start if the activity has been whitelisted by the
+     * Device Owner through DevicePolicyManager#setLockTaskComponents.
+     */
     public void startLockTask() {
         try {
             ActivityManagerNative.getDefault().startLockTaskMode(mToken);
@@ -5697,7 +5838,15 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Allow the user to switch away from the current task.
+     *
+     * Called to end the mode started by {@link Activity#startLockTask}. This
+     * can only be called by activities that have successfully called
+     * startLockTask previously.
+     *
+     * This will allow the user to exit this app and move onto other activities.
+     */
     public void stopLockTask() {
         try {
             ActivityManagerNative.getDefault().stopLockTaskMode();
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 5d809d8..044727d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -20,7 +20,6 @@
 import android.os.IBinder;
 import com.android.internal.app.IUsageStats;
 import com.android.internal.app.ProcessStats;
-import com.android.internal.os.PkgUsageStats;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.util.FastPrintWriter;
 
@@ -2130,14 +2129,15 @@
                 return new HashMap<String, Integer>();
             }
 
-            PkgUsageStats[] allPkgUsageStats = usageStatsService.getAllPkgUsageStats();
+            UsageStats.PackageStats[] allPkgUsageStats = usageStatsService.getAllPkgUsageStats(
+                    ActivityThread.currentPackageName());
             if (allPkgUsageStats == null) {
                 return new HashMap<String, Integer>();
             }
 
             Map<String, Integer> launchCounts = new HashMap<String, Integer>();
-            for (PkgUsageStats pkgUsageStats : allPkgUsageStats) {
-                launchCounts.put(pkgUsageStats.packageName, pkgUsageStats.launchCount);
+            for (UsageStats.PackageStats pkgUsageStats : allPkgUsageStats) {
+                launchCounts.put(pkgUsageStats.getPackageName(), pkgUsageStats.getLaunchCount());
             }
 
             return launchCounts;
@@ -2251,17 +2251,17 @@
      *
      * @hide
      */
-    public PkgUsageStats[] getAllPackageUsageStats() {
+    public UsageStats.PackageStats[] getAllPackageUsageStats() {
         try {
             IUsageStats usageStatsService = IUsageStats.Stub.asInterface(
                     ServiceManager.getService("usagestats"));
             if (usageStatsService != null) {
-                return usageStatsService.getAllPkgUsageStats();
+                return usageStatsService.getAllPkgUsageStats(ActivityThread.currentPackageName());
             }
         } catch (RemoteException e) {
             Log.w(TAG, "Could not query usage stats", e);
         }
-        return new PkgUsageStats[0];
+        return new UsageStats.PackageStats[0];
     }
 
     /**
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 57da21e..ec2868a 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -40,6 +40,7 @@
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StrictMode;
@@ -454,7 +455,8 @@
         case ACTIVITY_PAUSED_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
-            activityPaused(token);
+            PersistableBundle persistentState = data.readPersistableBundle();
+            activityPaused(token, persistentState);
             reply.writeNoException();
             return true;
         }
@@ -463,10 +465,9 @@
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
             Bundle map = data.readBundle();
-            Bitmap thumbnail = data.readInt() != 0
-                ? Bitmap.CREATOR.createFromParcel(data) : null;
+            PersistableBundle persistentState = data.readPersistableBundle();
             CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
-            activityStopped(token, map, thumbnail, description);
+            activityStopped(token, map, persistentState, description);
             reply.writeNoException();
             return true;
         }
@@ -2583,31 +2584,27 @@
         data.recycle();
         reply.recycle();
     }
-    public void activityPaused(IBinder token) throws RemoteException
+    public void activityPaused(IBinder token, PersistableBundle persistentState) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
+        data.writePersistableBundle(persistentState);
         mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
     }
     public void activityStopped(IBinder token, Bundle state,
-            Bitmap thumbnail, CharSequence description) throws RemoteException
+            PersistableBundle persistentState, CharSequence description) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
         data.writeBundle(state);
-        if (thumbnail != null) {
-            data.writeInt(1);
-            thumbnail.writeToParcel(data, 0);
-        } else {
-            data.writeInt(0);
-        }
+        data.writePersistableBundle(persistentState);
         TextUtils.writeToParcel(description, data, 0);
         mRemote.transact(ACTIVITY_STOPPED_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
         reply.readException();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3b2ff7f..161cb76 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -46,7 +46,7 @@
 import android.hardware.display.DisplayManagerGlobal;
 import android.net.IConnectivityManager;
 import android.net.Proxy;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
 import android.opengl.GLUtils;
 import android.os.AsyncTask;
 import android.os.Binder;
@@ -56,11 +56,11 @@
 import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.IRemoteCallback;
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
 import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -69,8 +69,6 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.transition.Scene;
-import android.transition.TransitionManager;
 import android.provider.Settings;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
@@ -268,6 +266,7 @@
         Intent intent;
         IVoiceInteractor voiceInteractor;
         Bundle state;
+        PersistableBundle persistentState;
         Activity activity;
         Window window;
         Activity parent;
@@ -317,6 +316,10 @@
             return false;
         }
 
+        public boolean isPersistable() {
+            return (activityInfo.flags & ActivityInfo.FLAG_PERSISTABLE) != 0;
+        }
+
         public String toString() {
             ComponentName componentName = intent != null ? intent.getComponent() : null;
             return "ActivityRecord{"
@@ -605,8 +608,8 @@
         // activity itself back to the activity manager. (matters more with ipc)
         public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                 ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
-                IVoiceInteractor voiceInteractor,
-                int procState, Bundle state, List<ResultInfo> pendingResults,
+                IVoiceInteractor voiceInteractor, int procState, Bundle state,
+                PersistableBundle persistentState, List<ResultInfo> pendingResults,
                 List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
                 String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
                 Bundle resumeArgs) {
@@ -622,6 +625,7 @@
             r.activityInfo = info;
             r.compatInfo = compatInfo;
             r.state = state;
+            r.persistentState = persistentState;
 
             r.pendingResults = pendingResults;
             r.pendingIntents = pendingNewIntents;
@@ -2205,7 +2209,11 @@
                 }
 
                 activity.mCalled = false;
-                mInstrumentation.callActivityOnCreate(activity, r.state);
+                if (r.isPersistable()) {
+                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
+                } else {
+                    mInstrumentation.callActivityOnCreate(activity, r.state);
+                }
                 if (!activity.mCalled) {
                     throw new SuperNotCalledException(
                         "Activity " + r.intent.getComponent().toShortString() +
@@ -2218,13 +2226,23 @@
                     r.stopped = false;
                 }
                 if (!r.activity.mFinished) {
-                    if (r.state != null) {
+                    if (r.isPersistable()) {
+                        if (r.state != null || r.persistentState != null) {
+                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
+                                    r.persistentState);
+                        }
+                    } else if (r.state != null) {
                         mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                     }
                 }
                 if (!r.activity.mFinished) {
                     activity.mCalled = false;
-                    mInstrumentation.callActivityOnPostCreate(activity, r.state);
+                    if (r.isPersistable()) {
+                        mInstrumentation.callActivityOnPostCreate(activity, r.state,
+                                r.persistentState);
+                    } else {
+                        mInstrumentation.callActivityOnPostCreate(activity, r.state);
+                    }
                     if (!activity.mCalled) {
                         throw new SuperNotCalledException(
                             "Activity " + r.intent.getComponent().toShortString() +
@@ -2842,6 +2860,7 @@
                 r.paused = false;
                 r.stopped = false;
                 r.state = null;
+                r.persistentState = null;
             } catch (Exception e) {
                 if (!mInstrumentation.onException(r.activity, e)) {
                     throw new RuntimeException(
@@ -3069,7 +3088,7 @@
 
             // Tell the activity manager we have paused.
             try {
-                ActivityManagerNative.getDefault().activityPaused(token);
+                ActivityManagerNative.getDefault().activityPaused(token, r.persistentState);
             } catch (RemoteException ex) {
             }
         }
@@ -3099,17 +3118,13 @@
                     + r.intent.getComponent().toShortString());
             Slog.e(TAG, e.getMessage(), e);
         }
-        Bundle state = null;
         if (finished) {
             r.activity.mFinished = true;
         }
         try {
             // Next have the activity save its current state and managed dialogs...
             if (!r.activity.mFinished && saveState) {
-                state = new Bundle();
-                state.setAllowFds(false);
-                mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
-                r.state = state;
+                callCallActivityOnSaveInstanceState(r);
             }
             // Now we are idle.
             r.activity.mCalled = false;
@@ -3145,7 +3160,7 @@
             listeners.get(i).onPaused(r.activity);
         }
 
-        return state;
+        return !r.activity.mFinished && saveState ? r.state : null;
     }
 
     final void performStopActivity(IBinder token, boolean saveState) {
@@ -3156,7 +3171,7 @@
     private static class StopInfo implements Runnable {
         ActivityClientRecord activity;
         Bundle state;
-        Bitmap thumbnail;
+        PersistableBundle persistentState;
         CharSequence description;
 
         @Override public void run() {
@@ -3164,7 +3179,7 @@
             try {
                 if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + activity);
                 ActivityManagerNative.getDefault().activityStopped(
-                    activity.token, state, thumbnail, description);
+                    activity.token, state, persistentState, description);
             } catch (RemoteException ex) {
             }
         }
@@ -3203,7 +3218,6 @@
     private void performStopActivityInner(ActivityClientRecord r,
             StopInfo info, boolean keepShown, boolean saveState) {
         if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
-        Bundle state = null;
         if (r != null) {
             if (!keepShown && r.stopped) {
                 if (r.activity.mFinished) {
@@ -3223,7 +3237,6 @@
                     // First create a thumbnail for the activity...
                     // For now, don't create the thumbnail here; we are
                     // doing that by doing a screen snapshot.
-                    info.thumbnail = null; //createThumbnailBitmap(r);
                     info.description = r.activity.onCreateDescription();
                 } catch (Exception e) {
                     if (!mInstrumentation.onException(r.activity, e)) {
@@ -3238,12 +3251,7 @@
             // Next have the activity save its current state and managed dialogs...
             if (!r.activity.mFinished && saveState) {
                 if (r.state == null) {
-                    state = new Bundle();
-                    state.setAllowFds(false);
-                    mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
-                    r.state = state;
-                } else {
-                    state = r.state;
+                    callCallActivityOnSaveInstanceState(r);
                 }
             }
 
@@ -3319,6 +3327,7 @@
         // manager to proceed and allow us to go fully into the background.
         info.activity = r;
         info.state = r.state;
+        info.persistentState = r.persistentState;
         mH.post(info);
     }
 
@@ -3775,9 +3784,7 @@
             performPauseActivity(r.token, false, r.isPreHoneycomb());
         }
         if (r.state == null && !r.stopped && !r.isPreHoneycomb()) {
-            r.state = new Bundle();
-            r.state.setAllowFds(false);
-            mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
+            callCallActivityOnSaveInstanceState(r);
         }
 
         handleDestroyActivity(r.token, false, configChanges, true);
@@ -3807,6 +3814,18 @@
         handleLaunchActivity(r, currentIntent);
     }
 
+    private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
+        r.state = new Bundle();
+        r.state.setAllowFds(false);
+        if (r.isPersistable()) {
+            r.persistentState = new PersistableBundle();
+            mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
+                    r.persistentState);
+        } else {
+            mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
+        }
+    }
+
     ArrayList<ComponentCallbacks2> collectComponentCallbacks(
             boolean allActivities, Configuration newConfig) {
         ArrayList<ComponentCallbacks2> callbacks
@@ -4294,8 +4313,8 @@
             // crash if we can't get it.
             IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
             try {
-                ProxyProperties proxyProperties = service.getProxy();
-                Proxy.setHttpProxySystemProperty(proxyProperties);
+                ProxyInfo proxyInfo = service.getProxy();
+                Proxy.setHttpProxySystemProperty(proxyInfo);
             } catch (RemoteException e) {}
         }
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index b616c1e..d813dab 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.Manifest;
 import android.os.Binder;
 import android.os.IBinder;
 import android.util.ArrayMap;
@@ -184,8 +185,10 @@
     public static final int OP_MONITOR_LOCATION = 41;
     /** @hide Continually monitoring location data with a relatively high power request. */
     public static final int OP_MONITOR_HIGH_POWER_LOCATION = 42;
+    /** @hide Retrieve current usage stats via {@link UsageStatsManager}. */
+    public static final int OP_GET_USAGE_STATS = 43;
     /** @hide */
-    public static final int _NUM_OP = 43;
+    public static final int _NUM_OP = 44;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION =
@@ -252,6 +255,7 @@
             OP_WAKE_LOCK,
             OP_COARSE_LOCATION,
             OP_COARSE_LOCATION,
+            OP_GET_USAGE_STATS,
     };
 
     /**
@@ -302,6 +306,7 @@
             null,
             OPSTR_MONITOR_LOCATION,
             OPSTR_MONITOR_HIGH_POWER_LOCATION,
+            null,
     };
 
     /**
@@ -352,6 +357,7 @@
             "WAKE_LOCK",
             "MONITOR_LOCATION",
             "MONITOR_HIGH_POWER_LOCATION",
+            "GET_USAGE_STATS"
     };
 
     /**
@@ -402,6 +408,7 @@
             android.Manifest.permission.WAKE_LOCK,
             null, // no permission for generic location monitoring
             null, // no permission for high power location monitoring
+            android.Manifest.permission.PACKAGE_USAGE_STATS,
     };
 
     /**
@@ -451,6 +458,7 @@
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
             AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_IGNORED, // OP_GET_USAGE_STATS
     };
 
     /**
@@ -504,6 +512,7 @@
             false,
             false,
             false,
+            false,
     };
 
     private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 7f2fb59..e7902a9 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -29,6 +29,7 @@
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -141,6 +142,7 @@
                     data.readStrongBinder());
             int procState = data.readInt();
             Bundle state = data.readBundle();
+            PersistableBundle persistentState = data.readPersistableBundle();
             List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
             List<Intent> pi = data.createTypedArrayList(Intent.CREATOR);
             boolean notResumed = data.readInt() != 0;
@@ -151,9 +153,9 @@
             boolean autoStopProfiler = data.readInt() != 0;
             Bundle resumeArgs = data.readBundle();
             scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo,
-                    voiceInteractor, procState, state,
-                    ri, pi, notResumed, isForward, profileName, profileFd, autoStopProfiler,
-                    resumeArgs);
+                    voiceInteractor, procState, state, persistentState,
+                    ri, pi, notResumed, isForward, profileName, profileFd,
+                    autoStopProfiler, resumeArgs);
             return true;
         }
         
@@ -731,8 +733,8 @@
 
     public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
             ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
-            IVoiceInteractor voiceInteractor,
-            int procState, Bundle state, List<ResultInfo> pendingResults,
+            IVoiceInteractor voiceInteractor, int procState, Bundle state,
+            PersistableBundle persistentState, List<ResultInfo> pendingResults,
             List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
             String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
             Bundle resumeArgs)
@@ -748,6 +750,7 @@
         data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);
         data.writeInt(procState);
         data.writeBundle(state);
+        data.writePersistableBundle(persistentState);
         data.writeTypedList(pendingResults);
         data.writeTypedList(pendingNewIntents);
         data.writeInt(notResumed ? 1 : 0);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index c621696..801182d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import android.net.wifi.IWifiScanner;
+import android.net.wifi.WifiScanner;
 import android.os.Build;
 
 import com.android.internal.policy.PolicyManager;
@@ -589,6 +591,13 @@
                     return new WifiP2pManager(service);
                 }});
 
+        registerService(WIFI_SCANNING_SERVICE, new ServiceFetcher() {
+            public Object createService(ContextImpl ctx) {
+                IBinder b = ServiceManager.getService(WIFI_SCANNING_SERVICE);
+                IWifiScanner service = IWifiScanner.Stub.asInterface(b);
+                return new WifiScanner(ctx.getOuterContext(), service);
+            }});
+
         registerService(WINDOW_SERVICE, new ServiceFetcher() {
                 Display mDefaultDisplay;
                 public Object getService(ContextImpl ctx) {
@@ -669,6 +678,11 @@
                 return new NetworkScoreManager(ctx);
             }
         });
+
+        registerService(USAGE_STATS_SERVICE, new ServiceFetcher() {
+                public Object createService(ContextImpl ctx) {
+                return new UsageStatsManager(ctx.getOuterContext());
+        }});
     }
 
     static ContextImpl getImpl(Context context) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 2e9cdf3b7..074b427 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -45,6 +45,7 @@
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.StrictMode;
 import android.service.voice.IVoiceInteractionSession;
@@ -104,9 +105,9 @@
     public void activityResumed(IBinder token) throws RemoteException;
     public void activityIdle(IBinder token, Configuration config,
             boolean stopProfiling) throws RemoteException;
-    public void activityPaused(IBinder token) throws RemoteException;
+    public void activityPaused(IBinder token, PersistableBundle persistentState) throws RemoteException;
     public void activityStopped(IBinder token, Bundle state,
-            Bitmap thumbnail, CharSequence description) throws RemoteException;
+            PersistableBundle persistentState, CharSequence description) throws RemoteException;
     public void activitySlept(IBinder token) throws RemoteException;
     public void activityDestroyed(IBinder token) throws RemoteException;
     public String getCallingPackage(IBinder token) throws RemoteException;
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index fefba8a..a832034 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -28,6 +28,7 @@
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.IInterface;
@@ -58,8 +59,8 @@
     void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
             ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
             IVoiceInteractor voiceInteractor, int procState, Bundle state,
-            List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed,
-            boolean isForward,
+            PersistableBundle persistentState, List<ResultInfo> pendingResults,
+            List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
             String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
             Bundle resumeArgs)
             throws RemoteException;
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e58ccb8..bb3e002 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -30,6 +30,7 @@
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.os.PerformanceCollector;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -1061,15 +1062,7 @@
         return (Activity)cl.loadClass(className).newInstance();
     }
 
-    /**
-     * Perform calling of an activity's {@link Activity#onCreate}
-     * method.  The default implementation simply calls through to that method.
-     * 
-     * @param activity The activity being created.
-     * @param icicle The previously frozen state (or null) to pass through to
-     *               onCreate().
-     */
-    public void callActivityOnCreate(Activity activity, Bundle icicle) {
+    private void prePerformCreate(Activity activity) {
         if (mWaitingActivities != null) {
             synchronized (mSync) {
                 final int N = mWaitingActivities.size();
@@ -1083,9 +1076,9 @@
                 }
             }
         }
-        
-        activity.performCreate(icicle);
-        
+    }
+
+    private void postPerformCreate(Activity activity) {
         if (mActivityMonitors != null) {
             synchronized (mSync) {
                 final int N = mActivityMonitors.size();
@@ -1096,6 +1089,33 @@
             }
         }
     }
+
+    /**
+     * Perform calling of an activity's {@link Activity#onCreate}
+     * method.  The default implementation simply calls through to that method.
+     *
+     * @param activity The activity being created.
+     * @param icicle The previously frozen state (or null) to pass through to onCreate().
+     */
+    public void callActivityOnCreate(Activity activity, Bundle icicle) {
+        prePerformCreate(activity);
+        activity.performCreate(icicle);
+        postPerformCreate(activity);
+    }
+
+    /**
+     * Perform calling of an activity's {@link Activity#onCreate}
+     * method.  The default implementation simply calls through to that method.
+     *  @param activity The activity being created.
+     * @param icicle The previously frozen state (or null) to pass through to
+     * @param persistentState The previously persisted state (or null)
+     */
+    public void callActivityOnCreate(Activity activity, Bundle icicle,
+            PersistableBundle persistentState) {
+        prePerformCreate(activity);
+        activity.performCreate(icicle, persistentState);
+        postPerformCreate(activity);
+    }
     
     public void callActivityOnDestroy(Activity activity) {
       // TODO: the following block causes intermittent hangs when using startActivity
@@ -1130,7 +1150,7 @@
     /**
      * Perform calling of an activity's {@link Activity#onRestoreInstanceState}
      * method.  The default implementation simply calls through to that method.
-     * 
+     *
      * @param activity The activity being restored.
      * @param savedInstanceState The previously saved state being restored.
      */
@@ -1139,9 +1159,22 @@
     }
 
     /**
+     * Perform calling of an activity's {@link Activity#onRestoreInstanceState}
+     * method.  The default implementation simply calls through to that method.
+     *
+     * @param activity The activity being restored.
+     * @param savedInstanceState The previously saved state being restored.
+     * @param persistentState The previously persisted state (or null)
+     */
+    public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState,
+            PersistableBundle persistentState) {
+        activity.performRestoreInstanceState(savedInstanceState, persistentState);
+    }
+
+    /**
      * Perform calling of an activity's {@link Activity#onPostCreate} method.
      * The default implementation simply calls through to that method.
-     * 
+     *
      * @param activity The activity being created.
      * @param icicle The previously frozen state (or null) to pass through to
      *               onPostCreate().
@@ -1151,6 +1184,19 @@
     }
 
     /**
+     * Perform calling of an activity's {@link Activity#onPostCreate} method.
+     * The default implementation simply calls through to that method.
+     *
+     * @param activity The activity being created.
+     * @param icicle The previously frozen state (or null) to pass through to
+     *               onPostCreate().
+     */
+    public void callActivityOnPostCreate(Activity activity, Bundle icicle,
+            PersistableBundle persistentState) {
+        activity.onPostCreate(icicle, persistentState);
+    }
+
+    /**
      * Perform calling of an activity's {@link Activity#onNewIntent}
      * method.  The default implementation simply calls through to that method.
      * 
@@ -1215,7 +1261,7 @@
     /**
      * Perform calling of an activity's {@link Activity#onSaveInstanceState}
      * method.  The default implementation simply calls through to that method.
-     * 
+     *
      * @param activity The activity being saved.
      * @param outState The bundle to pass to the call.
      */
@@ -1224,6 +1270,18 @@
     }
 
     /**
+     * Perform calling of an activity's {@link Activity#onSaveInstanceState}
+     * method.  The default implementation simply calls through to that method.
+     *  @param activity The activity being saved.
+     * @param outState The bundle to pass to the call.
+     * @param outPersistentState The persistent bundle to pass to the call.
+     */
+    public void callActivityOnSaveInstanceState(Activity activity, Bundle outState,
+            PersistableBundle outPersistentState) {
+        activity.performSaveInstanceState(outState, outPersistentState);
+    }
+
+    /**
      * Perform calling of an activity's {@link Activity#onPause} method.  The
      * default implementation simply calls through to that method.
      * 
@@ -1428,7 +1486,7 @@
     }
 
     /**
-     * Like {@link #execStartActivity},
+     * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
      * but accepts an array of activities to be started.  Note that active
      * {@link ActivityMonitor} objects only match against the first activity in
      * the array.
@@ -1442,7 +1500,7 @@
     }
 
     /**
-     * Like {@link #execStartActivity},
+     * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
      * but accepts an array of activities to be started.  Note that active
      * {@link ActivityMonitor} objects only match against the first activity in
      * the array.
@@ -1545,7 +1603,8 @@
     }
 
     /**
-     * Like {@link #execStartActivity}, but for starting as a particular user.
+     * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
+     * but for starting as a particular user.
      *
      * @param who The Context from which the activity is being started.
      * @param contextThread The main thread of the Context from which the activity
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index aab6ed8..db91742a 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -44,8 +44,8 @@
      * you to disable / reenable the keyguard.
      */
     public class KeyguardLock {
-        private IBinder mToken = new Binder();
-        private String mTag;
+        private final IBinder mToken = new Binder();
+        private final String mTag;
 
         KeyguardLock(String tag) {
             mTag = tag;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 25a1493..bba6caf 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -17,7 +17,7 @@
 package android.app;
 
 import com.android.internal.R;
-import com.android.internal.util.LegacyNotificationUtil;
+import com.android.internal.util.NotificationColorUtil;
 
 import android.annotation.IntDef;
 import android.content.Context;
@@ -28,6 +28,7 @@
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.BadParcelableException;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -420,6 +421,21 @@
     @Priority
     public int priority;
 
+    /**
+     * Accent color (an ARGB integer like the constants in {@link android.graphics.Color})
+     * to be applied by the standard Style templates when presenting this notification.
+     *
+     * The current template design constructs a colorful header image by overlaying the
+     * {@link #icon} image (stenciled in white) atop a field of this color. Alpha components are
+     * ignored.
+     */
+    public int color = COLOR_DEFAULT;
+
+    /**
+     * Special value of {@link #color} telling the system not to decorate this notification with
+     * any special color but instead use default colors when presenting this notification.
+     */
+    public static final int COLOR_DEFAULT = 0; // AKA Color.TRANSPARENT
 
     /**
      * Sphere of visibility of this notification, which affects how and when the SystemUI reveals 
@@ -877,6 +893,8 @@
         if (parcel.readInt() != 0) {
             publicVersion = Notification.CREATOR.createFromParcel(parcel);
         }
+
+        color = parcel.readInt();
     }
 
     @Override
@@ -968,6 +986,8 @@
             this.publicVersion.cloneInto(that.publicVersion, heavy);
         }
 
+        that.color = this.color;
+
         if (!heavy) {
             that.lightenPayload(); // will clean out extras
         }
@@ -1110,6 +1130,8 @@
         } else {
             parcel.writeInt(0);
         }
+
+        parcel.writeInt(color);
     }
 
     /**
@@ -1218,6 +1240,7 @@
         sb.append(Integer.toHexString(this.defaults));
         sb.append(" flags=0x");
         sb.append(Integer.toHexString(this.flags));
+        sb.append(String.format(" color=0x%08x", this.color));
         sb.append(" category="); sb.append(this.category);
         if (actions != null) {
             sb.append(" ");
@@ -1309,9 +1332,10 @@
         private boolean mShowWhen = true;
         private int mVisibility = VISIBILITY_PRIVATE;
         private Notification mPublicVersion = null;
-        private boolean mQuantumTheme;
-        private final LegacyNotificationUtil mLegacyNotificationUtil;
+        private final NotificationColorUtil mColorUtil;
         private ArrayList<String> mPeople;
+        private boolean mPreQuantum;
+        private int mColor = COLOR_DEFAULT;
 
         /**
          * Constructs a new Builder with the defaults:
@@ -1341,12 +1365,8 @@
             mPriority = PRIORITY_DEFAULT;
             mPeople = new ArrayList<String>();
 
-            // TODO: Decide on targetSdk from calling app whether to use quantum theme.
-            mQuantumTheme = true;
-
-            // TODO: Decide on targetSdk from calling app whether to instantiate the processor at
-            // all.
-            mLegacyNotificationUtil = LegacyNotificationUtil.getInstance();
+            mPreQuantum = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.L;
+            mColorUtil = NotificationColorUtil.getInstance();
         }
 
         /**
@@ -1853,29 +1873,38 @@
             }
         }
 
+        /**
+         * Sets {@link Notification#color}.
+         *
+         * @param argb The accent color to use
+         *
+         * @return The same Builder.
+         */
+        public Builder setColor(int argb) {
+            mColor = argb;
+            return this;
+        }
+
         private RemoteViews applyStandardTemplate(int resId, boolean fitIn1U) {
             RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
             boolean showLine3 = false;
             boolean showLine2 = false;
             int smallIconImageViewId = R.id.icon;
-            if (!mQuantumTheme && mPriority < PRIORITY_LOW) {
-                contentView.setInt(R.id.icon,
-                        "setBackgroundResource", R.drawable.notification_template_icon_low_bg);
-                contentView.setInt(R.id.status_bar_latest_event_content,
-                        "setBackgroundResource", R.drawable.notification_bg_low);
+            if (mPriority < PRIORITY_LOW) {
+                // TODO: Low priority presentation
             }
             if (mLargeIcon != null) {
                 contentView.setImageViewBitmap(R.id.icon, mLargeIcon);
-                processLegacyLargeIcon(mLargeIcon, contentView);
+                processLargeIcon(mLargeIcon, contentView);
                 smallIconImageViewId = R.id.right_icon;
             }
             if (mSmallIcon != 0) {
                 contentView.setImageViewResource(smallIconImageViewId, mSmallIcon);
                 contentView.setViewVisibility(smallIconImageViewId, View.VISIBLE);
                 if (mLargeIcon != null) {
-                    processLegacySmallIcon(mSmallIcon, smallIconImageViewId, contentView);
+                    processSmallRightIcon(mSmallIcon, smallIconImageViewId, contentView);
                 } else {
-                    processLegacyLargeIcon(mSmallIcon, contentView);
+                    processSmallIconAsLarge(mSmallIcon, contentView);
                 }
 
             } else {
@@ -2035,12 +2064,12 @@
          *         doesn't create quantum notifications by itself) app.
          */
         private boolean isLegacy() {
-            return mLegacyNotificationUtil != null;
+            return mColorUtil != null;
         }
 
         private void processLegacyAction(Action action, RemoteViews button) {
             if (isLegacy()) {
-                if (mLegacyNotificationUtil.isGrayscale(mContext, action.icon)) {
+                if (mColorUtil.isGrayscale(mContext, action.icon)) {
                     button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0,
                             mContext.getResources().getColor(
                                     R.color.notification_action_legacy_color_filter),
@@ -2051,47 +2080,70 @@
 
         private CharSequence processLegacyText(CharSequence charSequence) {
             if (isLegacy()) {
-                return mLegacyNotificationUtil.invertCharSequenceColors(charSequence);
+                return mColorUtil.invertCharSequenceColors(charSequence);
             } else {
                 return charSequence;
             }
         }
 
-        private void processLegacyLargeIcon(int largeIconId, RemoteViews contentView) {
-            if (isLegacy()) {
-                processLegacyLargeIcon(
-                        mLegacyNotificationUtil.isGrayscale(mContext, largeIconId),
-                        contentView);
+        /**
+         * Apply any necessary background to smallIcons being used in the largeIcon spot.
+         */
+        private void processSmallIconAsLarge(int largeIconId, RemoteViews contentView) {
+            if (!isLegacy() || mColorUtil.isGrayscale(mContext, largeIconId)) {
+                applyLargeIconBackground(contentView);
             }
         }
 
-        private void processLegacyLargeIcon(Bitmap largeIcon, RemoteViews contentView) {
-            if (isLegacy()) {
-                processLegacyLargeIcon(
-                        mLegacyNotificationUtil.isGrayscale(largeIcon),
-                        contentView);
+        /**
+         * Apply any necessary background to a largeIcon if it's a fake smallIcon (that is,
+         * if it's grayscale).
+         */
+        // TODO: also check bounds, transparency, that sort of thing.
+        private void processLargeIcon(Bitmap largeIcon, RemoteViews contentView) {
+            if (!isLegacy() || mColorUtil.isGrayscale(largeIcon)) {
+                applyLargeIconBackground(contentView);
             }
         }
 
-        private void processLegacyLargeIcon(boolean isGrayscale, RemoteViews contentView) {
-            if (isLegacy() && isGrayscale) {
-                contentView.setInt(R.id.icon, "setBackgroundResource",
-                        R.drawable.notification_icon_legacy_bg_inset);
-            }
+        /**
+         * Add a colored circle behind the largeIcon slot.
+         */
+        private void applyLargeIconBackground(RemoteViews contentView) {
+            contentView.setInt(R.id.icon, "setBackgroundResource",
+                    R.drawable.notification_icon_legacy_bg_inset);
+
+            contentView.setDrawableParameters(
+                    R.id.icon,
+                    true,
+                    -1,
+                    mColor,
+                    PorterDuff.Mode.SRC_ATOP,
+                    -1);
         }
 
-        private void processLegacySmallIcon(int smallIconDrawableId, int smallIconImageViewId,
+        /**
+         * Recolor small icons when used in the R.id.right_icon slot.
+         */
+        private void processSmallRightIcon(int smallIconDrawableId, int smallIconImageViewId,
                 RemoteViews contentView) {
-            if (isLegacy()) {
-                if (mLegacyNotificationUtil.isGrayscale(mContext, smallIconDrawableId)) {
-                    contentView.setDrawableParameters(smallIconImageViewId, false, -1,
-                            mContext.getResources().getColor(
-                                    R.color.notification_action_legacy_color_filter),
-                            PorterDuff.Mode.MULTIPLY, -1);
-                }
+            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);
             }
         }
 
+        private int resolveColor() {
+            if (mColor == COLOR_DEFAULT) {
+                mColor = mContext.getResources().getColor(R.color.notification_icon_bg_color);
+            } else {
+                mColor |= 0xFF000000; // no alpha for custom colors
+            }
+            return mColor;
+        }
+
         /**
          * Apply the unstyled operations and return a new {@link Notification} object.
          * @hide
@@ -2102,6 +2154,9 @@
             n.icon = mSmallIcon;
             n.iconLevel = mSmallIconLevel;
             n.number = mNumber;
+
+            n.color = resolveColor();
+
             n.contentView = makeContentView();
             n.contentIntent = mContentIntent;
             n.deleteIntent = mDeleteIntent;
@@ -2207,45 +2262,31 @@
 
 
         private int getBaseLayoutResource() {
-            return mQuantumTheme
-                    ? R.layout.notification_template_quantum_base
-                    : R.layout.notification_template_base;
+            return R.layout.notification_template_quantum_base;
         }
 
         private int getBigBaseLayoutResource() {
-            return mQuantumTheme
-                    ? R.layout.notification_template_quantum_big_base
-                    : R.layout.notification_template_big_base;
+            return R.layout.notification_template_quantum_big_base;
         }
 
         private int getBigPictureLayoutResource() {
-            return mQuantumTheme
-                    ? R.layout.notification_template_quantum_big_picture
-                    : R.layout.notification_template_big_picture;
+            return R.layout.notification_template_quantum_big_picture;
         }
 
         private int getBigTextLayoutResource() {
-            return mQuantumTheme
-                    ? R.layout.notification_template_quantum_big_text
-                    : R.layout.notification_template_big_text;
+            return R.layout.notification_template_quantum_big_text;
         }
 
         private int getInboxLayoutResource() {
-            return mQuantumTheme
-                    ? R.layout.notification_template_quantum_inbox
-                    : R.layout.notification_template_inbox;
+            return R.layout.notification_template_quantum_inbox;
         }
 
         private int getActionLayoutResource() {
-            return mQuantumTheme
-                    ? R.layout.notification_quantum_action
-                    : R.layout.notification_action;
+            return R.layout.notification_quantum_action;
         }
 
         private int getActionTombstoneLayoutResource() {
-            return mQuantumTheme
-                    ? R.layout.notification_quantum_action_tombstone
-                    : R.layout.notification_action_tombstone;
+            return R.layout.notification_quantum_action_tombstone;
         }
     }
 
diff --git a/core/res/res/drawable/stat_sys_adb.xml b/core/java/android/app/UsageStats.aidl
similarity index 67%
rename from core/res/res/drawable/stat_sys_adb.xml
rename to core/java/android/app/UsageStats.aidl
index dfc8563..7dee70a 100644
--- a/core/res/res/drawable/stat_sys_adb.xml
+++ b/core/java/android/app/UsageStats.aidl
@@ -1,7 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 2013, 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.
@@ -15,9 +13,8 @@
  * 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/stat_sys_adb_am"
-        android:autoMirrored="true">
-</bitmap>
+package android.app;
+
+parcelable UsageStats;
+parcelable UsageStats.PackageStats;
diff --git a/core/java/android/app/UsageStats.java b/core/java/android/app/UsageStats.java
new file mode 100644
index 0000000..0aeba59
--- /dev/null
+++ b/core/java/android/app/UsageStats.java
@@ -0,0 +1,406 @@
+/*
+ * 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.app;
+
+import android.content.res.Configuration;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.util.ArrayMap;
+
+import java.util.Map;
+
+/**
+ * Snapshot of current usage stats data.
+ * @hide
+ */
+public class UsageStats implements Parcelable {
+    /** @hide */
+    public final ArrayMap<String, PackageStats> mPackages = new ArrayMap<String, PackageStats>();
+    /** @hide */
+    public final ArrayMap<Configuration, ConfigurationStats> mConfigurations
+            = new ArrayMap<Configuration, ConfigurationStats>();
+
+    public static class PackageStats implements Parcelable {
+        private final String mPackageName;
+        private int mLaunchCount;
+        private long mUsageTime;
+        private long mResumedTime;
+
+        /** @hide */
+        public final ArrayMap<String, Long> componentResumeTimes;
+
+        public static final Parcelable.Creator<PackageStats> CREATOR
+                = new Parcelable.Creator<PackageStats>() {
+            public PackageStats createFromParcel(Parcel in) {
+                return new PackageStats(in);
+            }
+
+            public PackageStats[] newArray(int size) {
+                return new PackageStats[size];
+            }
+        };
+
+        public String toString() {
+            return "PackageStats{"
+            + Integer.toHexString(System.identityHashCode(this))
+            + " " + mPackageName + "}";
+        }
+
+        /** @hide */
+        public PackageStats(String pkgName) {
+            mPackageName = pkgName;
+            componentResumeTimes = new ArrayMap<String, Long>();
+        }
+
+        /** @hide */
+        public PackageStats(String pkgName, int count, long time, Map<String, Long> lastResumeTimes) {
+            mPackageName = pkgName;
+            mLaunchCount = count;
+            mUsageTime = time;
+            componentResumeTimes = new ArrayMap<String, Long>();
+            componentResumeTimes.putAll(lastResumeTimes);
+        }
+
+        /** @hide */
+        public PackageStats(Parcel source) {
+            mPackageName = source.readString();
+            mLaunchCount = source.readInt();
+            mUsageTime = source.readLong();
+            final int N = source.readInt();
+            componentResumeTimes = new ArrayMap<String, Long>(N);
+            for (int i = 0; i < N; i++) {
+                String component = source.readString();
+                long lastResumeTime = source.readLong();
+                componentResumeTimes.put(component, lastResumeTime);
+            }
+        }
+
+        /** @hide */
+        public PackageStats(PackageStats pStats) {
+            mPackageName = pStats.mPackageName;
+            mLaunchCount = pStats.mLaunchCount;
+            mUsageTime = pStats.mUsageTime;
+            componentResumeTimes = new ArrayMap<String, Long>(pStats.componentResumeTimes);
+        }
+
+        /** @hide */
+        public void resume(boolean launched) {
+            if (launched) {
+                mLaunchCount++;
+            }
+            mResumedTime = SystemClock.elapsedRealtime();
+        }
+
+        /** @hide */
+        public void pause() {
+            if (mResumedTime > 0) {
+                mUsageTime += SystemClock.elapsedRealtime() - mResumedTime;
+            }
+            mResumedTime = 0;
+        }
+
+        public final String getPackageName() {
+            return mPackageName;
+        }
+
+        public final long getUsageTime(long elapsedRealtime) {
+            return mUsageTime + (mResumedTime > 0 ? (elapsedRealtime- mResumedTime) : 0);
+        }
+
+        public final int getLaunchCount() {
+            return mLaunchCount;
+        }
+
+        /** @hide */
+        public boolean clearUsageTimes() {
+            mLaunchCount = 0;
+            mUsageTime = 0;
+            return mResumedTime <= 0 && componentResumeTimes.isEmpty();
+        }
+
+        public final int describeContents() {
+            return 0;
+        }
+
+        public final void writeToParcel(Parcel dest, int parcelableFlags) {
+            writeToParcel(dest, parcelableFlags, 0);
+        }
+
+        final void writeToParcel(Parcel dest, int parcelableFlags, long elapsedRealtime) {
+            dest.writeString(mPackageName);
+            dest.writeInt(mLaunchCount);
+            dest.writeLong(elapsedRealtime > 0 ? getUsageTime(elapsedRealtime) : mUsageTime);
+            dest.writeInt(componentResumeTimes.size());
+            for (Map.Entry<String, Long> ent : componentResumeTimes.entrySet()) {
+                dest.writeString(ent.getKey());
+                dest.writeLong(ent.getValue());
+            }
+        }
+
+        /** @hide */
+        public void writeExtendedToParcel(Parcel dest, int parcelableFlags) {
+        }
+    }
+
+    public static class ConfigurationStats implements Parcelable {
+        private final Configuration mConfiguration;
+        private long mLastUsedTime;
+        private int mUsageCount;
+        private long mUsageTime;
+        private long mStartedTime;
+
+        public static final Parcelable.Creator<ConfigurationStats> CREATOR
+                = new Parcelable.Creator<ConfigurationStats>() {
+            public ConfigurationStats createFromParcel(Parcel in) {
+                return new ConfigurationStats(in);
+            }
+
+            public ConfigurationStats[] newArray(int size) {
+                return new ConfigurationStats[size];
+            }
+        };
+
+        public String toString() {
+            return "ConfigurationStats{"
+            + Integer.toHexString(System.identityHashCode(this))
+            + " " + mConfiguration + "}";
+        }
+
+        /** @hide */
+        public ConfigurationStats(Configuration config) {
+            mConfiguration = config;
+        }
+
+        /** @hide */
+        public ConfigurationStats(Parcel source) {
+            mConfiguration = Configuration.CREATOR.createFromParcel(source);
+            mLastUsedTime = source.readLong();
+            mUsageCount = source.readInt();
+            mUsageTime = source.readLong();
+        }
+
+        /** @hide */
+        public ConfigurationStats(ConfigurationStats pStats) {
+            mConfiguration = pStats.mConfiguration;
+            mLastUsedTime = pStats.mLastUsedTime;
+            mUsageCount = pStats.mUsageCount;
+            mUsageTime = pStats.mUsageTime;
+        }
+
+        public final Configuration getConfiguration() {
+            return mConfiguration;
+        }
+
+        public final long getLastUsedTime() {
+            return mLastUsedTime;
+        }
+
+        public final long getUsageTime(long elapsedRealtime) {
+            return mUsageTime + (mStartedTime > 0 ? (elapsedRealtime- mStartedTime) : 0);
+        }
+
+        public final int getUsageCount() {
+            return mUsageCount;
+        }
+
+        /** @hide */
+        public void start() {
+            mLastUsedTime = System.currentTimeMillis();
+            mUsageCount++;
+            mStartedTime = SystemClock.elapsedRealtime();
+        }
+
+        /** @hide */
+        public void stop() {
+            if (mStartedTime > 0) {
+                mUsageTime += SystemClock.elapsedRealtime() - mStartedTime;
+            }
+            mStartedTime = 0;
+        }
+
+        /** @hide */
+        public boolean clearUsageTimes() {
+            mUsageCount = 0;
+            mUsageTime = 0;
+            return mLastUsedTime == 0 && mStartedTime <= 0;
+        }
+
+        public final int describeContents() {
+            return 0;
+        }
+
+        public final void writeToParcel(Parcel dest, int parcelableFlags) {
+            writeToParcel(dest, parcelableFlags, 0);
+        }
+
+        final void writeToParcel(Parcel dest, int parcelableFlags, long elapsedRealtime) {
+            mConfiguration.writeToParcel(dest, parcelableFlags);
+            dest.writeLong(mLastUsedTime);
+            dest.writeInt(mUsageCount);
+            dest.writeLong(elapsedRealtime > 0 ? getUsageTime(elapsedRealtime) : mUsageTime);
+        }
+
+        /** @hide */
+        public void writeExtendedToParcel(Parcel dest, int parcelableFlags) {
+        }
+    }
+
+    /** @hide */
+    public UsageStats() {
+    }
+
+    /** @hide */
+    public UsageStats(Parcel source, boolean extended) {
+        int N = source.readInt();
+        for (int i=0; i<N; i++) {
+            PackageStats pkg = extended ? onNewPackageStats(source) : new PackageStats(source);
+            mPackages.put(pkg.getPackageName(), pkg);
+        }
+        N = source.readInt();
+        for (int i=0; i<N; i++) {
+            ConfigurationStats config = extended ? onNewConfigurationStats(source)
+                    : new ConfigurationStats(source);
+            mConfigurations.put(config.getConfiguration(), config);
+        }
+    }
+
+    public int getPackageStatsCount() {
+        return mPackages.size();
+    }
+
+    public PackageStats getPackageStatsAt(int index) {
+        return mPackages.valueAt(index);
+    }
+
+    public PackageStats getPackageStats(String pkgName) {
+        return mPackages.get(pkgName);
+    }
+
+    /** @hide */
+    public PackageStats getOrCreatePackageStats(String pkgName) {
+        PackageStats ps = mPackages.get(pkgName);
+        if (ps == null) {
+            ps = onNewPackageStats(pkgName);
+            mPackages.put(pkgName, ps);
+        }
+        return ps;
+    }
+
+    public int getConfigurationStatsCount() {
+        return mConfigurations.size();
+    }
+
+    public ConfigurationStats getConfigurationStatsAt(int index) {
+        return mConfigurations.valueAt(index);
+    }
+
+    public ConfigurationStats getConfigurationStats(Configuration config) {
+        return mConfigurations.get(config);
+    }
+
+    /** @hide */
+    public ConfigurationStats getOrCreateConfigurationStats(Configuration config) {
+        ConfigurationStats cs = mConfigurations.get(config);
+        if (cs == null) {
+            cs = onNewConfigurationStats(config);
+            mConfigurations.put(config, cs);
+        }
+        return cs;
+    }
+
+    /** @hide */
+    public void clearUsageTimes() {
+        for (int i=mPackages.size()-1; i>=0; i--) {
+            if (mPackages.valueAt(i).clearUsageTimes()) {
+                mPackages.removeAt(i);
+            }
+        }
+        for (int i=mConfigurations.size()-1; i>=0; i--) {
+            if (mConfigurations.valueAt(i).clearUsageTimes()) {
+                mConfigurations.removeAt(i);
+            }
+        }
+    }
+
+    /** @hide */
+    public PackageStats onNewPackageStats(String pkgName) {
+        return new PackageStats(pkgName);
+    }
+
+    /** @hide */
+    public PackageStats onNewPackageStats(Parcel source) {
+        return new PackageStats(source);
+    }
+
+    /** @hide */
+    public ConfigurationStats onNewConfigurationStats(Configuration config) {
+        return new ConfigurationStats(config);
+    }
+
+    /** @hide */
+    public ConfigurationStats onNewConfigurationStats(Parcel source) {
+        return new ConfigurationStats(source);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int parcelableFlags) {
+        writeToParcelInner(dest, parcelableFlags, false);
+    }
+
+    /** @hide */
+    public void writeExtendedToParcel(Parcel dest, int parcelableFlags) {
+        writeToParcelInner(dest, parcelableFlags, true);
+    }
+
+    private void writeToParcelInner(Parcel dest, int parcelableFlags, boolean extended) {
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
+
+        int N = mPackages.size();
+        dest.writeInt(N);
+        for (int i=0; i<N; i++) {
+            PackageStats ps = mPackages.valueAt(i);
+            ps.writeToParcel(dest, parcelableFlags, elapsedRealtime);
+            if (extended) {
+                ps.writeExtendedToParcel(dest, parcelableFlags);
+            }
+        }
+        N = mConfigurations.size();
+        dest.writeInt(N);
+        for (int i=0; i<N; i++) {
+            ConfigurationStats cs = mConfigurations.valueAt(i);
+            cs.writeToParcel(dest, parcelableFlags, elapsedRealtime);
+            if (extended) {
+                cs.writeExtendedToParcel(dest, parcelableFlags);
+            }
+        }
+    }
+
+    public static final Parcelable.Creator<UsageStats> CREATOR
+            = new Parcelable.Creator<UsageStats>() {
+        public UsageStats createFromParcel(Parcel in) {
+            return new UsageStats(in, false);
+        }
+
+        public UsageStats[] newArray(int size) {
+            return new UsageStats[size];
+        }
+    };
+}
diff --git a/core/java/android/app/UsageStatsManager.java b/core/java/android/app/UsageStatsManager.java
new file mode 100644
index 0000000..fbf9c3b
--- /dev/null
+++ b/core/java/android/app/UsageStatsManager.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.app;
+
+import android.content.Context;
+import android.os.ParcelableParcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import com.android.internal.app.IUsageStats;
+
+/**
+ * Access to usage stats data.
+ * @hide
+ */
+public class UsageStatsManager {
+    final Context mContext;
+    final IUsageStats mService;
+
+    /** @hide */
+    public UsageStatsManager(Context context) {
+        mContext = context;
+        mService = IUsageStats.Stub.asInterface(ServiceManager.getService(
+                Context.USAGE_STATS_SERVICE));
+    }
+
+    public UsageStats getCurrentStats() {
+        try {
+            ParcelableParcel in = mService.getCurrentStats(mContext.getOpPackageName());
+            if (in != null) {
+                return new UsageStats(in.getParcel(), false);
+            }
+        } catch (RemoteException e) {
+            // About to die.
+        }
+        return new UsageStats();
+    }
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 209c536..58049fd 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16,8 +16,6 @@
 
 package android.app.admin;
 
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.ComponentName;
@@ -39,6 +37,8 @@
 
 import com.android.org.conscrypt.TrustedCertificateStore;
 
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.net.InetSocketAddress;
@@ -359,8 +359,8 @@
     }
 
     /**
-     * Retrieve the current minimum password quality for all admins
-     * or a particular one.
+     * Retrieve the current minimum password quality for all admins of this user
+     * and its profiles or a particular one.
      * @param admin The name of the admin component to check, or null to aggregate
      * all admins.
      */
@@ -412,8 +412,8 @@
     }
 
     /**
-     * Retrieve the current minimum password length for all admins
-     * or a particular one.
+     * Retrieve the current minimum password length for all admins of this
+     * user and its profiles or a particular one.
      * @param admin The name of the admin component to check, or null to aggregate
      * all admins.
      */
@@ -467,8 +467,9 @@
 
     /**
      * Retrieve the current number of upper case letters required in the
-     * password for all admins or a particular one. This is the same value as
-     * set by {#link {@link #setPasswordMinimumUpperCase(ComponentName, int)}
+     * password for all admins of this user and its profiles or a particular one.
+     * This is the same value as set by
+     * {#link {@link #setPasswordMinimumUpperCase(ComponentName, int)}
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
@@ -527,8 +528,9 @@
 
     /**
      * Retrieve the current number of lower case letters required in the
-     * password for all admins or a particular one. This is the same value as
-     * set by {#link {@link #setPasswordMinimumLowerCase(ComponentName, int)}
+     * password for all admins of this user and its profiles or a particular one.
+     * This is the same value as set by
+     * {#link {@link #setPasswordMinimumLowerCase(ComponentName, int)}
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
@@ -644,8 +646,9 @@
 
     /**
      * Retrieve the current number of numerical digits required in the password
-     * for all admins or a particular one. This is the same value as
-     * set by {#link {@link #setPasswordMinimumNumeric(ComponentName, int)}
+     * for all admins of this user and its profiles or a particular one.
+     * This is the same value as set by
+     * {#link {@link #setPasswordMinimumNumeric(ComponentName, int)}
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
@@ -760,8 +763,9 @@
 
     /**
      * Retrieve the current number of non-letter characters required in the
-     * password for all admins or a particular one. This is the same value as
-     * set by {#link {@link #setPasswordMinimumNonLetter(ComponentName, int)}
+     * password for all admins of this user and its profiles or a particular one.
+     * This is the same value as set by
+     * {#link {@link #setPasswordMinimumNonLetter(ComponentName, int)}
      * and only applies when the password quality is
      * {@link #PASSWORD_QUALITY_COMPLEX}.
      *
@@ -868,9 +872,10 @@
 
     /**
      * Get the current password expiration time for the given admin or an aggregate of
-     * all admins if admin is null. If the password is expired, this will return the time since
-     * the password expired as a negative number.  If admin is null, then a composite of all
-     * expiration timeouts is returned - which will be the minimum of all timeouts.
+     * all admins of this user and its profiles if admin is null. If the password is
+     * expired, this will return the time since the password expired as a negative number.
+     * If admin is null, then a composite of all expiration timeouts is returned
+     * - which will be the minimum of all timeouts.
      *
      * @param admin The name of the admin component to check, or null to aggregate all admins.
      * @return The password expiration time, in ms.
@@ -887,8 +892,8 @@
     }
 
     /**
-     * Retrieve the current password history length for all admins
-     * or a particular one.
+     * Retrieve the current password history length for all admins of this
+     * user and its profiles or a particular one.
      * @param admin The name of the admin component to check, or null to aggregate
      * all admins.
      * @return The length of the password history
@@ -923,14 +928,13 @@
     /**
      * Determine whether the current password the user has set is sufficient
      * to meet the policy requirements (quality, minimum length) that have been
-     * requested.
+     * requested by the admins of this user and its profiles.
      *
      * <p>The calling device admin must have requested
      * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call
      * this method; if it has not, a security exception will be thrown.
      *
-     * @return Returns true if the password meets the current requirements,
-     * else false.
+     * @return Returns true if the password meets the current requirements, else false.
      */
     public boolean isActivePasswordSufficient() {
         if (mService != null) {
@@ -993,7 +997,7 @@
 
     /**
      * Retrieve the current maximum number of login attempts that are allowed
-     * before the device wipes itself, for all admins
+     * before the device wipes itself, for all admins of this user and its profiles
      * or a particular one.
      * @param admin The name of the admin component to check, or null to aggregate
      * all admins.
@@ -1037,6 +1041,8 @@
      * {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call
      * this method; if it has not, a security exception will be thrown.
      *
+     * Can not be called from a managed profile.
+     *
      * @param password The new password for the user.
      * @param flags May be 0 or {@link #RESET_PASSWORD_REQUIRE_ENTRY}.
      * @return Returns true if the password was applied, or false if it is
@@ -1077,8 +1083,8 @@
     }
 
     /**
-     * Retrieve the current maximum time to unlock for all admins
-     * or a particular one.
+     * Retrieve the current maximum time to unlock for all admins of this user
+     * and its profiles or a particular one.
      * @param admin The name of the admin component to check, or null to aggregate
      * all admins.
      */
@@ -2062,6 +2068,28 @@
     }
 
     /**
+     * Called by a profile owner to disable account management for a specific type of account.
+     *
+     * <p>The calling device admin must be a profile owner. If it is not, a
+     * security exception will be thrown.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param accountType For which account management is disabled or enabled.
+     * @param disabled The boolean indicating that account management will be disabled (true) or
+     * enabled (false).
+     */
+    public void setAccountManagementDisabled(ComponentName admin, String accountType,
+            boolean disabled) {
+        if (mService != null) {
+            try {
+                mService.setAccountManagementDisabled(admin, accountType, disabled);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
      * Called by profile or device owner to re-enable system apps by intent that were disabled
      * by default when the managed profile was created. This should only be called from a profile
      * or device owner running within a managed profile.
@@ -2081,4 +2109,73 @@
         }
         return 0;
     }
+
+    /**
+     * Gets the array of accounts for which account management is disabled by the profile owner.
+     *
+     * <p> Account management can be disabled/enabled by calling
+     * {@link #setAccountManagementDisabled}.
+     *
+     * @return a list of account types for which account management has been disabled.
+     *
+     * @see #setAccountManagementDisabled
+     */
+    public String[] getAccountTypesWithManagementDisabled() {
+        if (mService != null) {
+            try {
+                return mService.getAccountTypesWithManagementDisabled();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Sets which components may enter lock task mode.
+     *
+     * This function can only be called by the device owner or the profile owner.
+     * @param components The list of components allowed to enter lock task mode
+     */
+    public void setLockTaskComponents(ComponentName[] components) throws SecurityException {
+        if (mService != null) {
+            try {
+                mService.setLockTaskComponents(components);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
+     * This function returns the list of components allowed to start the lock task mode.
+     * @hide
+     */
+    public ComponentName[] getLockTaskComponents() {
+        if (mService != null) {
+            try {
+                return mService.getLockTaskComponents();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * This function lets the caller know whether the given component is allowed to start the
+     * lock task mode.
+     * @param component The component to check
+     */
+    public boolean isLockTaskPermitted(ComponentName component) {
+        if (mService != null) {
+            try {
+                return mService.isLockTaskPermitted(component);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return false;
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b30f1b9..03ced0f 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -126,4 +126,11 @@
 
     void enableSystemApp(in ComponentName admin, in String packageName);
     int enableSystemAppWithIntent(in ComponentName admin, in Intent intent);
+
+    void setAccountManagementDisabled(in ComponentName who, in String accountType, in boolean disabled);
+    String[] getAccountTypesWithManagementDisabled();
+
+    void setLockTaskComponents(in ComponentName[] components);
+    ComponentName[] getLockTaskComponents();
+    boolean isLockTaskPermitted(in ComponentName component);
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 7c625bd..a059e48 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1982,6 +1982,7 @@
             WIFI_SERVICE,
             WIFI_HOTSPOT_SERVICE,
             WIFI_P2P_SERVICE,
+            WIFI_SCANNING_SERVICE,
             NSD_SERVICE,
             AUDIO_SERVICE,
             MEDIA_ROUTER_SERVICE,
@@ -2054,6 +2055,9 @@
      *  <dt> {@link #WIFI_SERVICE} ("wifi")
      *  <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of
      * Wi-Fi connectivity.
+     *  <dt> {@link #WIFI_P2P_SERVICE} ("wifip2p")
+     *  <dd> A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of
+     * Wi-Fi Direct connectivity.
      * <dt> {@link #INPUT_METHOD_SERVICE} ("input_method")
      * <dd> An {@link android.view.inputmethod.InputMethodManager InputMethodManager}
      * for management of input methods.
@@ -2357,6 +2361,16 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
+     * android.net.wifi.WifiScanner} for scanning the wifi universe
+     *
+     * @see #getSystemService
+     * @see android.net.wifi.WifiScanner
+     * @hide
+     */
+    public static final String WIFI_SCANNING_SERVICE = "wifiscanner";
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a {@link
      * android.net.nsd.NsdManager} for handling management of network service
      * discovery
      *
@@ -2669,6 +2683,16 @@
     public static final String NETWORK_SCORE_SERVICE = "network_score";
 
     /**
+     * Use with {@link #getSystemService} to retrieve a {@link
+     * android.app.UsageStatsManager} for interacting with the status bar.
+     *
+     * @see #getSystemService
+     * @see android.app.UsageStatsManager
+     * @hide
+     */
+    public static final String USAGE_STATS_SERVICE = "usagestats";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/SyncRequest.java b/core/java/android/content/SyncRequest.java
index a9a62a7..9ba45ca 100644
--- a/core/java/android/content/SyncRequest.java
+++ b/core/java/android/content/SyncRequest.java
@@ -473,7 +473,7 @@
          *   SyncRequest.Builder builder =
          *     new SyncRequest.Builder()
          *       .setSyncAdapter(dummyAccount, dummyProvider)
-         *       .syncOnce(5 * MINUTES_IN_SECS);
+         *       .syncOnce();
          *
          *   for (String syncData : syncItems) {
          *     Bundle extras = new Bundle();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1a003ff..eb2c11f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -936,13 +936,21 @@
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device has at least one camera pointing in
-     * some direction.
+     * some direction, or can support an external camera being connected to it.
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_CAMERA_ANY = "android.hardware.camera.any";
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device can support having an external camera connected to it.
+     * The external camera may not always be connected or available to applications to use.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_CAMERA_EXTERNAL = "android.hardware.camera.external";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device's camera supports flash.
      */
     @SdkConstant(SdkConstantType.FEATURE)
@@ -1083,6 +1091,13 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device includes a heart rate monitor.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device has a telephony radio with data
      * communication support.
      */
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index d80ab7b..ff96c51 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3600,10 +3600,13 @@
         // For use by the package manager to keep track of the path to the
         // file an app came from.
         public String mScanPath;
-        
-        // For use by package manager to keep track of where it has done dexopt.
-        public boolean mDidDexOpt;
-        
+
+        // For use by package manager to keep track of where it needs to do dexopt.
+        public boolean mDexOptNeeded = true;
+
+        // For use by package manager to keep track of when a package was last used.
+        public long mLastPackageUsageTimeInMills;
+
         // // User set enabled state.
         // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
         //
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 28309d7..5f2af8cf 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1277,20 +1277,6 @@
             new Key<Integer>("android.sensor.orientation", int.class);
 
     /**
-     * <p>The number of input samples for each dimension of
-     * {@link CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP android.sensor.profileHueSatMap}.</p>
-     * <p>The number of input samples for the hue, saturation, and value
-     * dimension of {@link CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP android.sensor.profileHueSatMap}. The order of the
-     * dimensions given is hue, saturation, value; where hue is the 0th
-     * element.</p>
-     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
-     *
-     * @see CaptureResult#SENSOR_PROFILE_HUE_SAT_MAP
-     */
-    public static final Key<int[]> SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS =
-            new Key<int[]>("android.sensor.profileHueSatMapDimensions", int[].class);
-
-    /**
      * <p>Optional. Defaults to [OFF]. Lists the supported test
      * pattern modes for {@link CaptureRequest#SENSOR_TEST_PATTERN_MODE android.sensor.testPatternMode}.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index f161f3a..0ca9161 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -458,7 +458,19 @@
      * brightness</p>
      * <p>For example, if EV step is 0.333, '6' will mean an
      * exposure compensation of +2 EV; -3 will mean an exposure
-     * compensation of -1</p>
+     * compensation of -1 EV. Note that this control will only be effective
+     * if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF. This control will take effect even when
+     * {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} <code>== true</code>.</p>
+     * <p>In the event of exposure compensation value being changed, camera device
+     * may take several frames to reach the newly requested exposure target.
+     * During that time, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} field will be in the SEARCHING
+     * state. Once the new exposure target is reached, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} will
+     * change from SEARCHING to either CONVERGED, LOCKED (if AE lock is enabled), or
+     * FLASH_REQUIRED (if the scene is too dark for still capture).</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_LOCK
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureResult#CONTROL_AE_STATE
      */
     public static final Key<Integer> CONTROL_AE_EXPOSURE_COMPENSATION =
             new Key<Integer>("android.control.aeExposureCompensation", int.class);
@@ -469,6 +481,8 @@
      * <p>Note that even when AE is locked, the flash may be
      * fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
      * ON_AUTO_FLASH_REDEYE.</p>
+     * <p>When {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION android.control.aeExposureCompensation} is changed, even if the AE lock
+     * is ON, the camera device will still adjust its exposure value.</p>
      * <p>If AE precapture is triggered (see {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger})
      * when AE is already locked, the camera device will not change the exposure time
      * ({@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}) and sensitivity ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity})
@@ -477,6 +491,7 @@
      * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.</p>
      * <p>See {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE lock related state transition details.</p>
      *
+     * @see CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
      * @see CaptureResult#CONTROL_AE_STATE
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 1d2d0e9..42a3de8 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -275,7 +275,19 @@
      * brightness</p>
      * <p>For example, if EV step is 0.333, '6' will mean an
      * exposure compensation of +2 EV; -3 will mean an exposure
-     * compensation of -1</p>
+     * compensation of -1 EV. Note that this control will only be effective
+     * if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} <code>!=</code> OFF. This control will take effect even when
+     * {@link CaptureRequest#CONTROL_AE_LOCK android.control.aeLock} <code>== true</code>.</p>
+     * <p>In the event of exposure compensation value being changed, camera device
+     * may take several frames to reach the newly requested exposure target.
+     * During that time, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} field will be in the SEARCHING
+     * state. Once the new exposure target is reached, {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} will
+     * change from SEARCHING to either CONVERGED, LOCKED (if AE lock is enabled), or
+     * FLASH_REQUIRED (if the scene is too dark for still capture).</p>
+     *
+     * @see CaptureRequest#CONTROL_AE_LOCK
+     * @see CaptureRequest#CONTROL_AE_MODE
+     * @see CaptureResult#CONTROL_AE_STATE
      */
     public static final Key<Integer> CONTROL_AE_EXPOSURE_COMPENSATION =
             new Key<Integer>("android.control.aeExposureCompensation", int.class);
@@ -286,6 +298,8 @@
      * <p>Note that even when AE is locked, the flash may be
      * fired if the {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_AUTO_FLASH / ON_ALWAYS_FLASH /
      * ON_AUTO_FLASH_REDEYE.</p>
+     * <p>When {@link CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION android.control.aeExposureCompensation} is changed, even if the AE lock
+     * is ON, the camera device will still adjust its exposure value.</p>
      * <p>If AE precapture is triggered (see {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger})
      * when AE is already locked, the camera device will not change the exposure time
      * ({@link CaptureRequest#SENSOR_EXPOSURE_TIME android.sensor.exposureTime}) and sensitivity ({@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity})
@@ -294,6 +308,7 @@
      * {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} is ON_ALWAYS_FLASH, the scene may become overexposed.</p>
      * <p>See {@link CaptureResult#CONTROL_AE_STATE android.control.aeState} for AE lock related state transition details.</p>
      *
+     * @see CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION
      * @see CaptureRequest#CONTROL_AE_MODE
      * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
      * @see CaptureResult#CONTROL_AE_STATE
@@ -1906,36 +1921,6 @@
             new Key<Rational[]>("android.sensor.neutralColorPoint", Rational[].class);
 
     /**
-     * <p>A mapping containing a hue shift, saturation scale, and value scale
-     * for each pixel.</p>
-     * <p>hue_samples, saturation_samples, and value_samples are given in
-     * {@link CameraCharacteristics#SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS android.sensor.profileHueSatMapDimensions}.</p>
-     * <p>Each entry of this map contains three floats corresponding to the
-     * hue shift, saturation scale, and value scale, respectively; where the
-     * hue shift has the lowest index. The map entries are stored in the tag
-     * in nested loop order, with the value divisions in the outer loop, the
-     * hue divisions in the middle loop, and the saturation divisions in the
-     * inner loop. All zero input saturation entries are required to have a
-     * value scale factor of 1.0.</p>
-     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
-     *
-     * @see CameraCharacteristics#SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS
-     */
-    public static final Key<float[]> SENSOR_PROFILE_HUE_SAT_MAP =
-            new Key<float[]>("android.sensor.profileHueSatMap", float[].class);
-
-    /**
-     * <p>A list of x,y samples defining a tone-mapping curve for gamma adjustment.</p>
-     * <p>This tag contains a default tone curve that can be applied while
-     * processing the image as a starting point for user adjustments.
-     * The curve is specified as a list of value pairs in linear gamma.
-     * The curve is interpolated using a cubic spline.</p>
-     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
-     */
-    public static final Key<float[]> SENSOR_PROFILE_TONE_CURVE =
-            new Key<float[]>("android.sensor.profileToneCurve", float[].class);
-
-    /**
      * <p>The worst-case divergence between Bayer green channels.</p>
      * <p>This value is an estimate of the worst case split between the
      * Bayer green channels in the red and blue rows in the sensor color
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index cec90cd..e58c54d 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -156,6 +156,9 @@
         // If true, enables automatic brightness control.
         public boolean useAutoBrightness;
 
+        //If true, scales the brightness to half of desired.
+        public boolean lowPowerMode;
+
         // If true, prevents the screen from completely turning on if it is currently off.
         // The display does not enter a "ready" state if this flag is true and screen on is
         // blocked.  The window manager policy blocks screen on while it prepares the keyguard to
@@ -203,6 +206,7 @@
             screenAutoBrightnessAdjustment = other.screenAutoBrightnessAdjustment;
             useAutoBrightness = other.useAutoBrightness;
             blockScreenOn = other.blockScreenOn;
+            lowPowerMode = other.lowPowerMode;
         }
 
         @Override
@@ -218,7 +222,8 @@
                     && screenBrightness == other.screenBrightness
                     && screenAutoBrightnessAdjustment == other.screenAutoBrightnessAdjustment
                     && useAutoBrightness == other.useAutoBrightness
-                    && blockScreenOn == other.blockScreenOn;
+                    && blockScreenOn == other.blockScreenOn
+                    && lowPowerMode == other.lowPowerMode;
         }
 
         @Override
@@ -233,7 +238,8 @@
                     + ", screenBrightness=" + screenBrightness
                     + ", screenAutoBrightnessAdjustment=" + screenAutoBrightnessAdjustment
                     + ", useAutoBrightness=" + useAutoBrightness
-                    + ", blockScreenOn=" + blockScreenOn;
+                    + ", blockScreenOn=" + blockScreenOn
+                    + ", lowPowerMode=" + lowPowerMode;
         }
     }
 
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index 8437228..ed223d1 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -36,6 +36,7 @@
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.InputMethodSession;
+import android.view.inputmethod.CursorAnchorInfo;
 
 class IInputMethodSessionWrapper extends IInputMethodSession.Stub
         implements HandlerCaller.Callback {
@@ -46,6 +47,7 @@
     private static final int DO_UPDATE_EXTRACTED_TEXT = 67;
     private static final int DO_UPDATE_SELECTION = 90;
     private static final int DO_UPDATE_CURSOR = 95;
+    private static final int DO_UPDATE_CURSOR_ANCHOR_INFO = 99;
     private static final int DO_APP_PRIVATE_COMMAND = 100;
     private static final int DO_TOGGLE_SOFT_INPUT = 105;
     private static final int DO_FINISH_SESSION = 110;
@@ -108,6 +110,10 @@
                 mInputMethodSession.updateCursor((Rect)msg.obj);
                 return;
             }
+            case DO_UPDATE_CURSOR_ANCHOR_INFO: {
+                mInputMethodSession.updateCursorAnchorInfo((CursorAnchorInfo)msg.obj);
+                return;
+            }
             case DO_APP_PRIVATE_COMMAND: {
                 SomeArgs args = (SomeArgs)msg.obj;
                 mInputMethodSession.appPrivateCommand((String)args.arg1,
@@ -181,6 +187,12 @@
     }
 
     @Override
+    public void updateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
+        mCaller.executeOrSendMessage(
+                mCaller.obtainMessageO(DO_UPDATE_CURSOR_ANCHOR_INFO, cursorAnchorInfo));
+    }
+
+    @Override
     public void appPrivateCommand(String action, Bundle data) {
         mCaller.executeOrSendMessage(
                 mCaller.obtainMessageOO(DO_APP_PRIVATE_COMMAND, action, data));
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index f6438b4..4bccaf1 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -51,6 +51,7 @@
 import android.view.WindowManager.BadTokenException;
 import android.view.animation.AnimationUtils;
 import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
@@ -545,6 +546,17 @@
         public void toggleSoftInput(int showFlags, int hideFlags) {
             InputMethodService.this.onToggleSoftInput(showFlags, hideFlags);
         }
+
+        /**
+         * Call {@link InputMethodService#onUpdateCursorAnchorInfo
+         * InputMethodService.onUpdateCursorAnchorInfo()}.
+         */
+        public void updateCursorAnchorInfo(CursorAnchorInfo info) {
+            if (!isEnabled()) {
+                return;
+            }
+            InputMethodService.this.onUpdateCursorAnchorInfo(info);
+        }
     }
     
     /**
@@ -1717,6 +1729,17 @@
     }
 
     /**
+     * Called when the application has reported a new location of its text insertion point and
+     * characters in the composition string.  This is only called if explicitly requested by the
+     * input method. The default implementation does nothing.
+     * @param cursorAnchorInfo The positional information of the text insertion point and the
+     * composition string.
+     */
+    public void onUpdateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) {
+        // Intentionally empty
+    }
+
+    /**
      * Update the cursor/anthor monitor mode.
      */
     public void setCursorAnchorMonitorMode(int monitorMode) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 3da00b1..30d7043 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1307,14 +1307,13 @@
      * doing something unusual like general internal filtering this may be useful.  On
      * a private network where the proxy is not accessible, you may break HTTP using this.
      *
-     * @param p The a {@link ProxyProperties} object defining the new global
+     * @param p The a {@link ProxyInfo} object defining the new global
      *        HTTP proxy.  A {@code null} value will clear the global HTTP proxy.
      *
      * <p>This method requires the call to hold the permission
-     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}.
-     * {@hide}
+     * android.Manifest.permission#CONNECTIVITY_INTERNAL.
      */
-    public void setGlobalProxy(ProxyProperties p) {
+    public void setGlobalProxy(ProxyInfo p) {
         try {
             mService.setGlobalProxy(p);
         } catch (RemoteException e) {
@@ -1324,14 +1323,13 @@
     /**
      * Retrieve any network-independent global HTTP proxy.
      *
-     * @return {@link ProxyProperties} for the current global HTTP proxy or {@code null}
+     * @return {@link ProxyInfo} for the current global HTTP proxy or {@code null}
      *        if no global HTTP proxy is set.
      *
      * <p>This method requires the call to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
-     * {@hide}
      */
-    public ProxyProperties getGlobalProxy() {
+    public ProxyInfo getGlobalProxy() {
         try {
             return mService.getGlobalProxy();
         } catch (RemoteException e) {
@@ -1343,14 +1341,14 @@
      * Get the HTTP proxy settings for the current default network.  Note that
      * if a global proxy is set, it will override any per-network setting.
      *
-     * @return the {@link ProxyProperties} for the current HTTP proxy, or {@code null} if no
+     * @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no
      *        HTTP proxy is active.
      *
      * <p>This method requires the call to hold the permission
      * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
      * {@hide}
      */
-    public ProxyProperties getProxy() {
+    public ProxyInfo getProxy() {
         try {
             return mService.getProxy();
         } catch (RemoteException e) {
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 381a817..d53a856 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -21,7 +21,7 @@
 import android.net.NetworkInfo;
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkState;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
 import android.os.IBinder;
 import android.os.Messenger;
 import android.os.ParcelFileDescriptor;
@@ -107,11 +107,11 @@
 
     void reportInetCondition(int networkType, int percentage);
 
-    ProxyProperties getGlobalProxy();
+    ProxyInfo getGlobalProxy();
 
-    void setGlobalProxy(in ProxyProperties p);
+    void setGlobalProxy(in ProxyInfo p);
 
-    ProxyProperties getProxy();
+    ProxyInfo getProxy();
 
     void setDataDependency(int networkType, boolean met);
 
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 4dfd3d9..2dcc544 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -16,7 +16,7 @@
 
 package android.net;
 
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
 import android.os.Parcelable;
 import android.os.Parcel;
 import android.text.TextUtils;
@@ -65,7 +65,7 @@
     private ArrayList<InetAddress> mDnses = new ArrayList<InetAddress>();
     private String mDomains;
     private ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
-    private ProxyProperties mHttpProxy;
+    private ProxyInfo mHttpProxy;
     private int mMtu;
 
     // Stores the properties of links that are "stacked" above this link.
@@ -101,7 +101,7 @@
             mDomains = source.getDomains();
             for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
             mHttpProxy = (source.getHttpProxy() == null)  ?
-                    null : new ProxyProperties(source.getHttpProxy());
+                    null : new ProxyInfo(source.getHttpProxy());
             for (LinkProperties l: source.mStackedLinks.values()) {
                 addStackedLink(l);
             }
@@ -295,10 +295,10 @@
         return routes;
     }
 
-    public void setHttpProxy(ProxyProperties proxy) {
+    public void setHttpProxy(ProxyInfo proxy) {
         mHttpProxy = proxy;
     }
-    public ProxyProperties getHttpProxy() {
+    public ProxyInfo getHttpProxy() {
         return mHttpProxy;
     }
 
@@ -720,7 +720,7 @@
                     netProp.addRoute((RouteInfo)in.readParcelable(null));
                 }
                 if (in.readByte() == 1) {
-                    netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
+                    netProp.setHttpProxy((ProxyInfo)in.readParcelable(null));
                 }
                 ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
                 in.readList(stackedLinks, LinkProperties.class.getClassLoader());
diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java
index bea8d1c..daf0065 100644
--- a/core/java/android/net/Proxy.java
+++ b/core/java/android/net/Proxy.java
@@ -19,6 +19,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
+import android.net.ProxyInfo;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -63,8 +64,11 @@
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
-    /** {@hide} **/
-    public static final String EXTRA_PROXY_INFO = "proxy";
+    /**
+     * Intent extra included with {@link #PROXY_CHANGE_ACTION} intents.
+     * It describes the new proxy being used (as a {@link ProxyInfo} object).
+     */
+    public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
 
     /** @hide */
     public static final int PROXY_VALID             = 0;
@@ -114,24 +118,14 @@
      */
     public static final java.net.Proxy getProxy(Context ctx, String url) {
         String host = "";
-        if (url != null) {
+        if ((url != null) && !isLocalHost(host)) {
             URI uri = URI.create(url);
-            host = uri.getHost();
-        }
+            ProxySelector proxySelector = ProxySelector.getDefault();
 
-        if (!isLocalHost(host)) {
-            if (sConnectivityManager == null) {
-                sConnectivityManager = (ConnectivityManager)ctx.getSystemService(
-                        Context.CONNECTIVITY_SERVICE);
-            }
-            if (sConnectivityManager == null) return java.net.Proxy.NO_PROXY;
+            List<java.net.Proxy> proxyList = proxySelector.select(uri);
 
-            ProxyProperties proxyProperties = sConnectivityManager.getProxy();
-
-            if (proxyProperties != null) {
-                if (!proxyProperties.isExcluded(host)) {
-                    return proxyProperties.makeProxy();
-                }
+            if (proxyList.size() > 0) {
+                return proxyList.get(0);
             }
         }
         return java.net.Proxy.NO_PROXY;
@@ -275,7 +269,7 @@
     }
 
     /** @hide */
-    public static final void setHttpProxySystemProperty(ProxyProperties p) {
+    public static final void setHttpProxySystemProperty(ProxyInfo p) {
         String host = null;
         String port = null;
         String exclList = null;
@@ -283,8 +277,10 @@
         if (p != null) {
             host = p.getHost();
             port = Integer.toString(p.getPort());
-            exclList = p.getExclusionList();
-            pacFileUrl = p.getPacFileUrl();
+            exclList = p.getExclusionListAsString();
+            if (p.getPacFileUrl() != null) {
+                pacFileUrl = p.getPacFileUrl().toString();
+            }
         }
         setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
     }
diff --git a/core/java/android/net/ProxyProperties.aidl b/core/java/android/net/ProxyInfo.aidl
similarity index 95%
rename from core/java/android/net/ProxyProperties.aidl
rename to core/java/android/net/ProxyInfo.aidl
index 02ea15d..2c91960 100644
--- a/core/java/android/net/ProxyProperties.aidl
+++ b/core/java/android/net/ProxyInfo.aidl
@@ -17,5 +17,5 @@
 
 package android.net;
 
-parcelable ProxyProperties;
+parcelable ProxyInfo;
 
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyInfo.java
similarity index 61%
rename from core/java/android/net/ProxyProperties.java
rename to core/java/android/net/ProxyInfo.java
index 50f45e8..b40941f 100644
--- a/core/java/android/net/ProxyProperties.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -21,14 +21,23 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import org.apache.http.client.HttpClient;
+
 import java.net.InetSocketAddress;
+import java.net.URLConnection;
+import java.util.List;
 import java.util.Locale;
 
 /**
- * A container class for the http proxy info
- * @hide
+ * Describes a proxy configuration.
+ *
+ * Proxy configurations are already integrated within the Apache HTTP stack.
+ * So {@link URLConnection} and {@link HttpClient} will use them automatically.
+ *
+ * Other HTTP stacks will need to obtain the proxy info from
+ * {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}.
  */
-public class ProxyProperties implements Parcelable {
+public class ProxyInfo implements Parcelable {
 
     private String mHost;
     private int mPort;
@@ -36,32 +45,82 @@
     private String[] mParsedExclusionList;
 
     private String mPacFileUrl;
+    /**
+     *@hide
+     */
     public static final String LOCAL_EXCL_LIST = "";
+    /**
+     *@hide
+     */
     public static final int LOCAL_PORT = -1;
+    /**
+     *@hide
+     */
     public static final String LOCAL_HOST = "localhost";
 
-    public ProxyProperties(String host, int port, String exclList) {
+    /**
+     * Constructs a {@link ProxyInfo} object that points at a Direct proxy
+     * on the specified host and port.
+     */
+    public static ProxyInfo buildDirectProxy(String host, int port) {
+        return new ProxyInfo(host, port, null);
+    }
+
+    /**
+     * Constructs a {@link ProxyInfo} object that points at a Direct proxy
+     * on the specified host and port.
+     *
+     * The proxy will not be used to access any host in exclusion list, exclList.
+     *
+     * @param exclList Hosts to exclude using the proxy on connections for.  These
+     *                 hosts can use wildcards such as *.example.com.
+     */
+    public static ProxyInfo buildDirectProxy(String host, int port, List<String> exclList) {
+        String[] array = exclList.toArray(new String[exclList.size()]);
+        return new ProxyInfo(host, port, TextUtils.join(",", array), array);
+    }
+
+    /**
+     * Construct a {@link ProxyInfo} that will download and run the PAC script
+     * at the specified URL.
+     */
+    public static ProxyInfo buildPacProxy(Uri pacUri) {
+        return new ProxyInfo(pacUri.toString());
+    }
+
+    /**
+     * Create a ProxyProperties that points at a HTTP Proxy.
+     * @hide
+     */
+    public ProxyInfo(String host, int port, String exclList) {
         mHost = host;
         mPort = port;
         setExclusionList(exclList);
     }
 
-    public ProxyProperties(String pacFileUrl) {
+    /**
+     * Create a ProxyProperties that points at a PAC URL.
+     * @hide
+     */
+    public ProxyInfo(String pacFileUrl) {
         mHost = LOCAL_HOST;
         mPort = LOCAL_PORT;
         setExclusionList(LOCAL_EXCL_LIST);
         mPacFileUrl = pacFileUrl;
     }
 
-    // Only used in PacManager after Local Proxy is bound.
-    public ProxyProperties(String pacFileUrl, int localProxyPort) {
+    /**
+     * Only used in PacManager after Local Proxy is bound.
+     * @hide
+     */
+    public ProxyInfo(String pacFileUrl, int localProxyPort) {
         mHost = LOCAL_HOST;
         mPort = localProxyPort;
         setExclusionList(LOCAL_EXCL_LIST);
         mPacFileUrl = pacFileUrl;
     }
 
-    private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) {
+    private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) {
         mHost = host;
         mPort = port;
         mExclusionList = exclList;
@@ -70,16 +129,22 @@
     }
 
     // copy constructor instead of clone
-    public ProxyProperties(ProxyProperties source) {
+    /**
+     * @hide
+     */
+    public ProxyInfo(ProxyInfo source) {
         if (source != null) {
             mHost = source.getHost();
             mPort = source.getPort();
-            mPacFileUrl = source.getPacFileUrl();
-            mExclusionList = source.getExclusionList();
+            mPacFileUrl = source.mPacFileUrl;
+            mExclusionList = source.getExclusionListAsString();
             mParsedExclusionList = source.mParsedExclusionList;
         }
     }
 
+    /**
+     * @hide
+     */
     public InetSocketAddress getSocketAddress() {
         InetSocketAddress inetSocketAddress = null;
         try {
@@ -88,20 +153,46 @@
         return inetSocketAddress;
     }
 
-    public String getPacFileUrl() {
-        return mPacFileUrl;
+    /**
+     * Returns the URL of the current PAC script or null if there is
+     * no PAC script.
+     */
+    public Uri getPacFileUrl() {
+        if (TextUtils.isEmpty(mPacFileUrl)) {
+            return null;
+        }
+        return Uri.parse(mPacFileUrl);
     }
 
+    /**
+     * When configured to use a Direct Proxy this returns the host
+     * of the proxy.
+     */
     public String getHost() {
         return mHost;
     }
 
+    /**
+     * When configured to use a Direct Proxy this returns the port
+     * of the proxy
+     */
     public int getPort() {
         return mPort;
     }
 
-    // comma separated
-    public String getExclusionList() {
+    /**
+     * When configured to use a Direct Proxy this returns the list
+     * of hosts for which the proxy is ignored.
+     */
+    public String[] getExclusionList() {
+        return mParsedExclusionList;
+    }
+
+    /**
+     * comma separated
+     * @hide
+     */
+    public String getExclusionListAsString() {
         return mExclusionList;
     }
 
@@ -111,33 +202,13 @@
         if (mExclusionList == null) {
             mParsedExclusionList = new String[0];
         } else {
-            String splitExclusionList[] = exclusionList.toLowerCase(Locale.ROOT).split(",");
-            mParsedExclusionList = new String[splitExclusionList.length * 2];
-            for (int i = 0; i < splitExclusionList.length; i++) {
-                String s = splitExclusionList[i].trim();
-                if (s.startsWith(".")) s = s.substring(1);
-                mParsedExclusionList[i*2] = s;
-                mParsedExclusionList[(i*2)+1] = "." + s;
-            }
+            mParsedExclusionList = exclusionList.toLowerCase(Locale.ROOT).split(",");
         }
     }
 
-    public boolean isExcluded(String url) {
-        if (TextUtils.isEmpty(url) || mParsedExclusionList == null ||
-                mParsedExclusionList.length == 0) return false;
-
-        Uri u = Uri.parse(url);
-        String urlDomain = u.getHost();
-        if (urlDomain == null) return false;
-        for (int i = 0; i< mParsedExclusionList.length; i+=2) {
-            if (urlDomain.equals(mParsedExclusionList[i]) ||
-                    urlDomain.endsWith(mParsedExclusionList[i+1])) {
-                return true;
-            }
-        }
-        return false;
-    }
-
+    /**
+     * @hide
+     */
     public boolean isValid() {
         if (!TextUtils.isEmpty(mPacFileUrl)) return true;
         return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost,
@@ -145,6 +216,9 @@
                                                 mExclusionList == null ? "" : mExclusionList);
     }
 
+    /**
+     * @hide
+     */
     public java.net.Proxy makeProxy() {
         java.net.Proxy proxy = java.net.Proxy.NO_PROXY;
         if (mHost != null) {
@@ -179,17 +253,17 @@
 
     @Override
     public boolean equals(Object o) {
-        if (!(o instanceof ProxyProperties)) return false;
-        ProxyProperties p = (ProxyProperties)o;
+        if (!(o instanceof ProxyInfo)) return false;
+        ProxyInfo p = (ProxyInfo)o;
         // If PAC URL is present in either then they must be equal.
         // Other parameters will only be for fall back.
         if (!TextUtils.isEmpty(mPacFileUrl)) {
             return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort;
         }
-        if (!TextUtils.isEmpty(p.getPacFileUrl())) {
+        if (!TextUtils.isEmpty(p.mPacFileUrl)) {
             return false;
         }
-        if (mExclusionList != null && !mExclusionList.equals(p.getExclusionList())) return false;
+        if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) return false;
         if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) {
             return false;
         }
@@ -245,15 +319,15 @@
      * Implement the Parcelable interface.
      * @hide
      */
-    public static final Creator<ProxyProperties> CREATOR =
-        new Creator<ProxyProperties>() {
-            public ProxyProperties createFromParcel(Parcel in) {
+    public static final Creator<ProxyInfo> CREATOR =
+        new Creator<ProxyInfo>() {
+            public ProxyInfo createFromParcel(Parcel in) {
                 String host = null;
                 int port = 0;
                 if (in.readByte() != 0) {
                     String url = in.readString();
                     int localPort = in.readInt();
-                    return new ProxyProperties(url, localPort);
+                    return new ProxyInfo(url, localPort);
                 }
                 if (in.readByte() != 0) {
                     host = in.readString();
@@ -261,13 +335,13 @@
                 }
                 String exclList = in.readString();
                 String[] parsedExclList = in.readStringArray();
-                ProxyProperties proxyProperties =
-                        new ProxyProperties(host, port, exclList, parsedExclList);
+                ProxyInfo proxyProperties =
+                        new ProxyInfo(host, port, exclList, parsedExclList);
                 return proxyProperties;
             }
 
-            public ProxyProperties[] newArray(int size) {
-                return new ProxyProperties[size];
+            public ProxyInfo[] newArray(int size) {
+                return new ProxyInfo[size];
             }
         };
 }
diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl
index ae9796b..521f4fd 100644
--- a/core/java/android/nfc/INfcCardEmulation.aidl
+++ b/core/java/android/nfc/INfcCardEmulation.aidl
@@ -34,4 +34,6 @@
     AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category);
     boolean removeAidGroupForService(int userHandle, in ComponentName service, String category);
     List<ApduServiceInfo> getServices(int userHandle, in String category);
+    boolean setPreferredService(in ComponentName service);
+    boolean unsetPreferredService();
 }
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
index 2820f40..b0449224 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -12,10 +12,15 @@
 import android.util.Log;
 
 /**
- * The AidGroup class represents a group of ISO/IEC 7816-4
- * Application Identifiers (AIDs) for a specific application
- * category, along with a description resource describing
- * the group.
+ * The AidGroup class represents a group of Application Identifiers (AIDs).
+ *
+ * <p>An instance of this object can be used with
+ * {@link CardEmulation#registerAidGroupForService(android.content.ComponentName, AidGroup)}
+ * to tell the OS which AIDs are handled by your HCE- or SE-based service.
+ *
+ * <p>The format of AIDs is defined in the ISO/IEC 7816-4 specification. This class
+ * requires the AIDs to be input as a hexadecimal string, with an even amount of
+ * hexadecimal characters, e.g. "F014811481".
  */
 public final class AidGroup implements Parcelable {
     /**
@@ -33,7 +38,7 @@
      * Creates a new AidGroup object.
      *
      * @param aids The list of AIDs present in the group
-     * @param category The category of this group
+     * @param category The category of this group, e.g. {@link CardEmulation#CATEGORY_PAYMENT}
      */
     public AidGroup(ArrayList<String> aids, String category) {
         if (aids == null || aids.size() == 0) {
@@ -42,11 +47,12 @@
         if (aids.size() > MAX_NUM_AIDS) {
             throw new IllegalArgumentException("Too many AIDs in AID group.");
         }
-        if (!isValidCategory(category)) {
-            throw new IllegalArgumentException("Category specified is not valid.");
+        if (isValidCategory(category)) {
+            this.category = category;
+        } else {
+            this.category = CardEmulation.CATEGORY_OTHER;
         }
         this.aids = aids;
-        this.category = category;
         this.description = null;
     }
 
@@ -158,7 +164,7 @@
         }
     }
 
-    boolean isValidCategory(String category) {
+    static boolean isValidCategory(String category) {
         return CardEmulation.CATEGORY_PAYMENT.equals(category) ||
                 CardEmulation.CATEGORY_OTHER.equals(category);
     }
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 94f35ed..f379ee8 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -290,6 +290,20 @@
         return groups;
     }
 
+    /**
+     * Returns the category to which this service has attributed the AID that is passed in,
+     * or null if we don't know this AID.
+     */
+    public String getCategoryForAid(String aid) {
+        ArrayList<AidGroup> groups = getAidGroups();
+        for (AidGroup group : groups) {
+            if (group.aids.contains(aid)) {
+                return group.category;
+            }
+        }
+        return null;
+    }
+
     public boolean hasCategory(String category) {
         return (mStaticAidGroups.containsKey(category) || mDynamicAidGroups.containsKey(category));
     }
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index 41f039c..e24a22a 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Activity;
 import android.app.ActivityThread;
 import android.content.ComponentName;
 import android.content.Context;
@@ -28,6 +29,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
 import android.util.Log;
 
 import java.util.HashMap;
@@ -248,6 +250,33 @@
     }
 
     /**
+     * Returns whether the user has allowed AIDs registered in the
+     * specified category to be handled by a service that is preferred
+     * by the foreground application, instead of by a pre-configured default.
+     *
+     * Foreground applications can set such preferences using the
+     * {@link #setPreferredService(Activity, ComponentName)} method.
+     *
+     * @param category The category, e.g. {@link #CATEGORY_PAYMENT}
+     * @return whether AIDs in the category can be handled by a service
+     *         specified by the foreground app.
+     */
+    public boolean categoryAllowsForegroundPreference(String category) {
+        if (CATEGORY_PAYMENT.equals(category)) {
+            boolean preferForeground = false;
+            try {
+                preferForeground = Settings.Secure.getInt(mContext.getContentResolver(),
+                        Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0;
+            } catch (SettingNotFoundException e) {
+            }
+            return preferForeground;
+        } else {
+            // Allowed for all other categories
+            return true;
+        }
+    }
+
+    /**
      * Returns the service selection mode for the passed in category.
      * Valid return values are:
      * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default
@@ -269,7 +298,6 @@
                 return SELECTION_MODE_ALWAYS_ASK;
             }
         } else {
-            // All other categories are in "only ask if conflict" mode
             return SELECTION_MODE_ASK_IF_CONFLICT;
         }
     }
@@ -283,7 +311,7 @@
      * that AID group will be replaced with this one.
      *
      * <p>Note that you can only register AIDs for a service that
-     * is running under the same UID as you are. Typically
+     * is running under the same UID as the caller of this API. Typically
      * this means you need to call this from the same
      * package as the service itself, though UIDs can also
      * be shared between packages using shared UIDs.
@@ -352,7 +380,7 @@
      * method. It will *not* remove AID groups that were statically registered in
      * the manifest. If a dynamically registered AID group is removed using
      * this method, and a statically registered AID group for the same category
-     * exists in the manifest, that AID group will become active again.
+     * exists in the manifest, the static AID group will become active again.
      *
      * @param service The component name of the service
      * @param category The category of the AID group to be removed, e.g. {@link #CATEGORY_PAYMENT}
@@ -378,6 +406,96 @@
     }
 
     /**
+     * Allows a foreground application to specify which card emulation service
+     * should be preferred while a specific Activity is in the foreground.
+     *
+     * <p>The specified Activity must currently be in resumed state. A good
+     * paradigm is to call this method in your {@link Activity#onResume}, and to call
+     * {@link #unsetPreferredService(Activity)} in your {@link Activity#onPause}.
+     *
+     * <p>This method call will fail in two specific scenarios:
+     * <ul>
+     * <li> If the service registers one or more AIDs in the {@link #CATEGORY_PAYMENT}
+     * category, but the user has indicated that foreground apps are not allowed
+     * to override the default payment service.
+     * <li> If the service registers one or more AIDs in the {@link #CATEGORY_OTHER}
+     * category that are also handled by the default payment service, and the
+     * user has indicated that foreground apps are not allowed to override the
+     * default payment service.
+     * </ul>
+     *
+     * <p> Use {@link #categoryAllowsForegroundPreference(String)} to determine
+     * whether foreground apps can override the default payment service.
+     *
+     * <p>Note that this preference is not persisted by the OS, and hence must be
+     * called every time the Activity is resumed.
+     *
+     * @param activity The activity which prefers this service to be invoked
+     * @param service The service to be preferred while this activity is in the foreground
+     * @return whether the registration was successful
+     */
+    public boolean setPreferredService(Activity activity, ComponentName service) {
+        // Verify the activity is in the foreground before calling into NfcService
+        if (activity == null || service == null) {
+            throw new NullPointerException("activity or service or category is null");
+        }
+        if (!activity.isResumed()) {
+            throw new IllegalArgumentException("Activity must be resumed.");
+        }
+        try {
+            return sService.setPreferredService(service);
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.setPreferredService(service);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Unsets the preferred service for the specified Activity.
+     *
+     * <p>Note that the specified Activity must still be in resumed
+     * state at the time of this call. A good place to call this method
+     * is in your {@link Activity#onPause} implementation.
+     *
+     * @param activity The activity which the service was registered for
+     * @return true when successful
+     */
+    public boolean unsetPreferredService(Activity activity) {
+        if (activity == null) {
+            throw new NullPointerException("activity is null");
+        }
+        if (!activity.isResumed()) {
+            throw new IllegalArgumentException("Activity must be resumed.");
+        }
+        try {
+            return sService.unsetPreferredService();
+        } catch (RemoteException e) {
+            // Try one more time
+            recoverService();
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover CardEmulationService.");
+                return false;
+            }
+            try {
+                return sService.unsetPreferredService();
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to reach CardEmulationService.");
+                return false;
+            }
+        }
+    }
+
+    /**
      * @hide
      */
     public boolean setDefaultServiceForCategory(ComponentName service, String category) {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index e78ce33..4857533 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -21,6 +21,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Formatter;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -30,6 +31,8 @@
 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;
 import com.android.internal.os.BatteryStatsHelper;
@@ -135,7 +138,7 @@
     /**
      * Bump the version on this if the checkin format changes.
      */
-    private static final int BATTERY_STATS_CHECKIN_VERSION = 7;
+    private static final int BATTERY_STATS_CHECKIN_VERSION = 8;
     
     private static final long BYTES_PER_KB = 1024;
     private static final long BYTES_PER_MB = 1048576; // 1024^2
@@ -537,6 +540,7 @@
         public static final byte CMD_START = 4;
         public static final byte CMD_CURRENT_TIME = 5;
         public static final byte CMD_OVERFLOW = 6;
+        public static final byte CMD_RESET = 7;
 
         public byte cmd = CMD_NULL;
         
@@ -620,6 +624,8 @@
         public static final int EVENT_SYNC = 0x0004;
         // Number of event types.
         public static final int EVENT_COUNT = 0x0005;
+        // Mask to extract out only the type part of the event.
+        public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
 
         public static final int EVENT_PROC_START = EVENT_PROC | EVENT_FLAG_START;
         public static final int EVENT_PROC_FINISH = EVENT_PROC | EVENT_FLAG_FINISH;
@@ -684,7 +690,7 @@
                 dest.writeInt(eventCode);
                 eventTag.writeToParcel(dest, flags);
             }
-            if (cmd == CMD_CURRENT_TIME) {
+            if (cmd == CMD_CURRENT_TIME || cmd == CMD_RESET) {
                 dest.writeLong(currentTime);
             }
         }
@@ -722,7 +728,7 @@
                 eventCode = EVENT_NONE;
                 eventTag = null;
             }
-            if (cmd == CMD_CURRENT_TIME) {
+            if (cmd == CMD_CURRENT_TIME || cmd == CMD_RESET) {
                 currentTime = src.readLong();
             } else {
                 currentTime = 0;
@@ -833,7 +839,59 @@
             return true;
         }
     }
-    
+
+    public final static class HistoryEventTracker {
+        private final HashMap<String, SparseIntArray>[] mActiveEvents
+                = (HashMap<String, SparseIntArray>[]) new HashMap[HistoryItem.EVENT_COUNT];
+
+        public boolean updateState(int code, String name, int uid, int poolIdx) {
+            if ((code&HistoryItem.EVENT_FLAG_START) != 0) {
+                int idx = code&HistoryItem.EVENT_TYPE_MASK;
+                HashMap<String, SparseIntArray> active = mActiveEvents[idx];
+                if (active == null) {
+                    active = new HashMap<String, SparseIntArray>();
+                    mActiveEvents[idx] = active;
+                }
+                SparseIntArray uids = active.get(name);
+                if (uids == null) {
+                    uids = new SparseIntArray();
+                    active.put(name, uids);
+                }
+                if (uids.indexOfKey(uid) >= 0) {
+                    // Already set, nothing to do!
+                    return false;
+                }
+                uids.put(uid, poolIdx);
+            } else if ((code&HistoryItem.EVENT_FLAG_FINISH) != 0) {
+                int idx = code&HistoryItem.EVENT_TYPE_MASK;
+                HashMap<String, SparseIntArray> active = mActiveEvents[idx];
+                if (active == null) {
+                    // not currently active, nothing to do.
+                    return false;
+                }
+                SparseIntArray uids = active.get(name);
+                if (uids == null) {
+                    // not currently active, nothing to do.
+                    return false;
+                }
+                idx = uids.indexOfKey(uid);
+                if (idx < 0) {
+                    // not currently active, nothing to do.
+                    return false;
+                }
+                uids.removeAt(idx);
+                if (uids.size() <= 0) {
+                    active.remove(name);
+                }
+            }
+            return true;
+        }
+
+        public HashMap<String, SparseIntArray> getStateForEvent(int code) {
+            return mActiveEvents[code];
+        }
+    }
+
     public static final class BitDescription {
         public final int mask;
         public final int shift;
@@ -861,7 +919,7 @@
             this.shortValues = shortValues;
         }
     }
-    
+
     public abstract int getHistoryTotalSize();
 
     public abstract int getHistoryUsedSize();
@@ -2958,10 +3016,14 @@
                     pw.print(":");
                 }
                 pw.println("START");
-            } else if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) {
+            } else if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
+                    || rec.cmd == HistoryItem.CMD_RESET) {
                 if (checkin) {
                     pw.print(":");
                 }
+                if (rec.cmd == HistoryItem.CMD_RESET) {
+                    pw.print("RESET:");
+                }
                 pw.print("TIME:");
                 if (checkin) {
                     pw.println(rec.currentTime);
@@ -3187,6 +3249,86 @@
     public static final int DUMP_INCLUDE_HISTORY = 1<<3;
     public static final int DUMP_VERBOSE = 1<<4;
 
+    private void dumpHistoryLocked(PrintWriter pw, int flags, long histStart, boolean checkin) {
+        final HistoryPrinter hprinter = new HistoryPrinter();
+        final HistoryItem rec = new HistoryItem();
+        long lastTime = -1;
+        long baseTime = -1;
+        boolean printed = false;
+        HistoryEventTracker tracker = null;
+        while (getNextHistoryLocked(rec)) {
+            lastTime = rec.time;
+            if (baseTime < 0) {
+                baseTime = lastTime;
+            }
+            if (rec.time >= histStart) {
+                if (histStart >= 0 && !printed) {
+                    if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
+                            || rec.cmd == HistoryItem.CMD_RESET) {
+                        printed = true;
+                    } 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;
+                        rec.eventTag = new HistoryTag();
+                        for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
+                            HashMap<String, SparseIntArray> active
+                                    = tracker.getStateForEvent(i);
+                            if (active == null) {
+                                continue;
+                            }
+                            for (HashMap.Entry<String, SparseIntArray> ent
+                                    : active.entrySet()) {
+                                SparseIntArray uids = ent.getValue();
+                                for (int j=0; j<uids.size(); j++) {
+                                    rec.eventCode = i;
+                                    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.eventCode = oldCode;
+                        rec.eventTag = oldTag;
+                        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) {
+                if (tracker == null) {
+                    tracker = new HistoryEventTracker();
+                }
+                tracker.updateState(rec.eventCode, rec.eventTag.string,
+                        rec.eventTag.uid, rec.eventTag.poolIdx);
+            }
+        }
+        if (histStart >= 0) {
+            pw.print(checkin ? "NEXT: " : "  NEXT: "); pw.println(lastTime+1);
+        }
+    }
+
     /**
      * Dumps a human-readable summary of the battery statistics to the given PrintWriter.
      *
@@ -3200,9 +3342,6 @@
                 (flags&(DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) != 0;
 
         if ((flags&DUMP_HISTORY_ONLY) != 0 || !filtering) {
-            long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
-
-            final HistoryItem rec = new HistoryItem();
             final long historyTotalSize = getHistoryTotalSize();
             final long historyUsedSize = getHistoryUsedSize();
             if (startIteratingHistoryLocked()) {
@@ -3218,35 +3357,7 @@
                     pw.print(" strings using ");
                     printSizeValue(pw, getHistoryStringPoolBytes());
                     pw.println("):");
-                    HistoryPrinter hprinter = new HistoryPrinter();
-                    long lastTime = -1;
-                    long baseTime = -1;
-                    boolean printed = false;
-                    while (getNextHistoryLocked(rec)) {
-                        lastTime = rec.time;
-                        if (baseTime < 0) {
-                            baseTime = lastTime;
-                        }
-                        if (rec.time >= histStart) {
-                            if (histStart >= 0 && !printed) {
-                                if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) {
-                                    printed = true;
-                                } else if (rec.currentTime != 0) {
-                                    printed = true;
-                                    byte cmd = rec.cmd;
-                                    rec.cmd = HistoryItem.CMD_CURRENT_TIME;
-                                    hprinter.printNextItem(pw, rec, baseTime, false,
-                                            (flags&DUMP_VERBOSE) != 0);
-                                    rec.cmd = cmd;
-                                }
-                            }
-                            hprinter.printNextItem(pw, rec, baseTime, false,
-                                    (flags&DUMP_VERBOSE) != 0);
-                        }
-                    }
-                    if (histStart >= 0) {
-                        pw.print("  NEXT: "); pw.println(lastTime+1);
-                    }
+                    dumpHistoryLocked(pw, flags, histStart, false);
                     pw.println();
                 } finally {
                     finishIteratingHistoryLocked();
@@ -3255,6 +3366,7 @@
 
             if (startIteratingOldHistoryLocked()) {
                 try {
+                    final HistoryItem rec = new HistoryItem();
                     pw.println("Old battery History:");
                     HistoryPrinter hprinter = new HistoryPrinter();
                     long baseTime = -1;
@@ -3348,7 +3460,6 @@
                 (flags&(DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY)) != 0;
 
         if ((flags&DUMP_INCLUDE_HISTORY) != 0 || (flags&DUMP_HISTORY_ONLY) != 0) {
-            final HistoryItem rec = new HistoryItem();
             if (startIteratingHistoryLocked()) {
                 try {
                     for (int i=0; i<getHistoryStringPoolSize(); i++) {
@@ -3365,37 +3476,7 @@
                         pw.print("\"");
                         pw.println();
                     }
-                    HistoryPrinter hprinter = new HistoryPrinter();
-                    long lastTime = -1;
-                    long baseTime = -1;
-                    boolean printed = false;
-                    while (getNextHistoryLocked(rec)) {
-                        lastTime = rec.time;
-                        if (baseTime < 0) {
-                            baseTime = lastTime;
-                        }
-                        if (rec.time >= histStart) {
-                            if (histStart >= 0 && !printed) {
-                                if (rec.cmd == HistoryItem.CMD_CURRENT_TIME) {
-                                    printed = true;
-                                } else if (rec.currentTime != 0) {
-                                    printed = true;
-                                    byte cmd = rec.cmd;
-                                    rec.cmd = HistoryItem.CMD_CURRENT_TIME;
-                                    pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
-                                    pw.print(HISTORY_DATA); pw.print(',');
-                                    hprinter.printNextItem(pw, rec, baseTime, true, false);
-                                    rec.cmd = cmd;
-                                }
-                            }
-                            pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
-                            pw.print(HISTORY_DATA); pw.print(',');
-                            hprinter.printNextItem(pw, rec, baseTime, true, false);
-                        }
-                    }
-                    if (histStart >= 0) {
-                        pw.print("NEXT: "); pw.println(lastTime+1);
-                    }
+                    dumpHistoryLocked(pw, flags, histStart, true);
                 } finally {
                     finishIteratingHistoryLocked();
                 }
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 899a958..cd47099 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -36,6 +36,7 @@
     Bitmap getUserIcon(int userHandle);
     List<UserInfo> getUsers(boolean excludeDying);
     List<UserInfo> getProfiles(int userHandle, boolean enabledOnly);
+    UserInfo getProfileParent(int userHandle);
     UserInfo getUserInfo(int userHandle);
     boolean isRestricted();
     void setGuestEnabled(boolean enable);
diff --git a/core/java/android/net/ProxyProperties.aidl b/core/java/android/os/ParcelableParcel.aidl
similarity index 83%
copy from core/java/android/net/ProxyProperties.aidl
copy to core/java/android/os/ParcelableParcel.aidl
index 02ea15d..61f730c 100644
--- a/core/java/android/net/ProxyProperties.aidl
+++ b/core/java/android/os/ParcelableParcel.aidl
@@ -1,6 +1,5 @@
 /*
-**
-** Copyright (C) 2010 The Android Open Source Project
+** 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.
@@ -15,7 +14,6 @@
 ** limitations under the License.
 */
 
-package android.net;
+package android.os;
 
-parcelable ProxyProperties;
-
+parcelable ParcelableParcel;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 84639eb..312cdbe 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -234,6 +234,38 @@
      */
     public static final String DISALLOW_CONFIG_APPS = "no_config_apps";
 
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from mounting
+     * physical external media. The default value is <code>false</code>.
+     * <p/>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from adjusting microphone
+     * volume.
+     * The default value is <code>false</code>.
+     * <p/>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
+
+    /**
+     * Key for user restrictions. Specifies if a user is disallowed from adjusting the master
+     * volume.
+     * The default value is <code>false</code>.
+     * <p/>
+     * Type: Boolean
+     * @see #setUserRestrictions(Bundle)
+     * @see #getUserRestrictions()
+     */
+    public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
+
     /** @hide */
     public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
     /** @hide */
@@ -269,7 +301,8 @@
     }
 
     /**
-     * Returns the user handle for the user that this application is running for.
+     * Returns the user handle for the user that the calling process is running on.
+     *
      * @return the user handle of the user making this call.
      * @hide
      */
@@ -585,7 +618,8 @@
     }
 
     /**
-     * Returns a list of UserHandles for profiles associated with this user, including this user.
+     * Returns a list of UserHandles for profiles associated with the user that the calling process
+     * is running on, including the user itself.
      *
      * @return A non-empty list of UserHandles associated with the calling user.
      */
@@ -606,6 +640,21 @@
     }
 
     /**
+     * Returns the parent of the profile which this method is called from
+     * or null if called from a user that is not a profile.
+     *
+     * @hide
+     */
+    public UserInfo getProfileParent(int userHandle) {
+        try {
+            return mService.getProfileParent(userHandle);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get profile parent", re);
+            return null;
+        }
+    }
+
+    /**
      * If the target user is a managed profile of the calling user or the caller
      * is itself a managed profile, then this returns a badged copy of the given
      * icon to be able to distinguish it from the original icon.
@@ -632,7 +681,7 @@
 
     private int getBadgeResIdForUser(int userHandle) {
         // Return the framework-provided badge.
-        List<UserInfo> userProfiles = getProfiles(UserHandle.myUserId());
+        List<UserInfo> userProfiles = getProfiles(getUserHandle());
         for (UserInfo user : userProfiles) {
             if (user.id == userHandle
                     && user.isManagedProfile()) {
@@ -661,7 +710,7 @@
     /**
      * Returns information for all users on this device. Requires
      * {@link android.Manifest.permission#MANAGE_USERS} permission.
-     * 
+     *
      * @param excludeDying specify if the list should exclude users being
      *            removed.
      * @return the list of users that were created.
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index e4f73cb..811751d 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -167,7 +167,7 @@
 
         /**
          * Callback notifying that a print job state changed.
-         * 
+         *
          * @param printJobId The print job id.
          */
         public void onPrintJobStateChanged(PrintJobId printJobId);
@@ -175,7 +175,7 @@
 
     /**
      * Creates a new instance.
-     * 
+     *
      * @param context The current context in which to operate.
      * @param service The backing system service.
      * @hide
@@ -207,13 +207,17 @@
 
     /**
      * Creates an instance that can access all print jobs.
-     * 
+     *
      * @param userId The user id for which to get all print jobs.
      * @return An instance if the caller has the permission to access all print
      *         jobs, null otherwise.
      * @hide
      */
     public PrintManager getGlobalPrintManagerForUser(int userId) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return null;
+        }
         return new PrintManager(mContext, mService, userId, APP_ID_ANY);
     }
 
@@ -228,11 +232,15 @@
 
     /**
      * Adds a listener for observing the state of print jobs.
-     * 
+     *
      * @param listener The listener to add.
      * @hide
      */
     public void addPrintJobStateChangeListener(PrintJobStateChangeListener listener) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return;
+        }
         if (mPrintJobStateChangeListeners == null) {
             mPrintJobStateChangeListeners = new ArrayMap<PrintJobStateChangeListener,
                     PrintJobStateChangeListenerWrapper>();
@@ -249,11 +257,15 @@
 
     /**
      * Removes a listener for observing the state of print jobs.
-     * 
+     *
      * @param listener The listener to remove.
      * @hide
      */
     public void removePrintJobStateChangeListener(PrintJobStateChangeListener listener) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return;
+        }
         if (mPrintJobStateChangeListeners == null) {
             return;
         }
@@ -275,12 +287,16 @@
 
     /**
      * Gets a print job given its id.
-     * 
+     *
      * @return The print job list.
      * @see PrintJob
      * @hide
      */
     public PrintJob getPrintJob(PrintJobId printJobId) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return null;
+        }
         try {
             PrintJobInfo printJob = mService.getPrintJobInfo(printJobId, mAppId, mUserId);
             if (printJob != null) {
@@ -294,11 +310,15 @@
 
     /**
      * Gets the print jobs for this application.
-     * 
+     *
      * @return The print job list.
      * @see PrintJob
      */
     public List<PrintJob> getPrintJobs() {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return Collections.emptyList();
+        }
         try {
             List<PrintJobInfo> printJobInfos = mService.getPrintJobInfos(mAppId, mUserId);
             if (printJobInfos == null) {
@@ -317,6 +337,10 @@
     }
 
     void cancelPrintJob(PrintJobId printJobId) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return;
+        }
         try {
             mService.cancelPrintJob(printJobId, mAppId, mUserId);
         } catch (RemoteException re) {
@@ -325,6 +349,10 @@
     }
 
     void restartPrintJob(PrintJobId printJobId) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return;
+        }
         try {
             mService.restartPrintJob(printJobId, mAppId, mUserId);
         } catch (RemoteException re) {
@@ -383,6 +411,10 @@
      */
     public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter,
             PrintAttributes attributes) {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return null;
+        }
         if (!(mContext instanceof Activity)) {
             throw new IllegalStateException("Can print only from an activity");
         }
@@ -418,11 +450,15 @@
 
     /**
      * Gets the list of enabled print services.
-     * 
+     *
      * @return The enabled service list or an empty list.
      * @hide
      */
     public List<PrintServiceInfo> getEnabledPrintServices() {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return Collections.emptyList();
+        }
         try {
             List<PrintServiceInfo> enabledServices = mService.getEnabledPrintServices(mUserId);
             if (enabledServices != null) {
@@ -436,11 +472,15 @@
 
     /**
      * Gets the list of installed print services.
-     * 
+     *
      * @return The installed service list or an empty list.
      * @hide
      */
     public List<PrintServiceInfo> getInstalledPrintServices() {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return Collections.emptyList();
+        }
         try {
             List<PrintServiceInfo> installedServices = mService.getInstalledPrintServices(mUserId);
             if (installedServices != null) {
@@ -456,6 +496,10 @@
      * @hide
      */
     public PrinterDiscoverySession createPrinterDiscoverySession() {
+        if (mService == null) {
+            Log.w(LOG_TAG, "Feature android.software.print not available");
+            return null;
+        }
         return new PrinterDiscoverySession(mService, mContext, mUserId);
     }
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d5a3bcb..1847b55 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2823,7 +2823,6 @@
             MOVED_TO_GLOBAL.add(Settings.Global.TETHER_SUPPORTED);
             MOVED_TO_GLOBAL.add(Settings.Global.USB_MASS_STORAGE_ENABLED);
             MOVED_TO_GLOBAL.add(Settings.Global.USE_GOOGLE_MAIL);
-            MOVED_TO_GLOBAL.add(Settings.Global.WEB_AUTOFILL_QUERY_URL);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_COUNTRY_CODE);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_FREQUENCY_BAND);
@@ -2838,6 +2837,8 @@
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SAVED_STATE);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_SUSPEND_OPTIMIZATIONS_ENABLED);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_ENHANCED_AUTO_JOIN);
+            MOVED_TO_GLOBAL.add(Settings.Global.WIFI_NETWORK_SHOW_RSSI);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_ON);
             MOVED_TO_GLOBAL.add(Settings.Global.WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED);
             MOVED_TO_GLOBAL.add(Settings.Global.WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON);
@@ -4528,6 +4529,12 @@
         public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
 
         /**
+         * Whether NFC payment is handled by the foreground application or a default.
+         * @hide
+         */
+        public static final String NFC_PAYMENT_FOREGROUND = "nfc_payment_foreground";
+
+        /**
          * Specifies the package name currently configured to be the primary sms application
          * @hide
          */
@@ -5353,11 +5360,6 @@
         */
        public static final String USE_GOOGLE_MAIL = "use_google_mail";
 
-       /** Autofill server address (Used in WebView/browser).
-        * {@hide} */
-       public static final String WEB_AUTOFILL_QUERY_URL =
-           "web_autofill_query_url";
-
        /**
         * Whether Wifi display is enabled/disabled
         * 0=disabled. 1=enabled.
@@ -5469,7 +5471,21 @@
        public static final String WIFI_SUPPLICANT_SCAN_INTERVAL_MS =
                "wifi_supplicant_scan_interval_ms";
 
-       /**
+        /**
+         * whether frameworks handles wifi auto-join
+         * @hide
+         */
+       public static final String WIFI_ENHANCED_AUTO_JOIN =
+                "wifi_enhanced_auto_join";
+
+        /**
+         * whether settings show RSSI
+         * @hide
+         */
+        public static final String WIFI_NETWORK_SHOW_RSSI =
+                "wifi_network_show_rssi";
+
+        /**
         * The interval in milliseconds to scan at supplicant when p2p is connected
         * @hide
         */
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 2549fde..49a0138 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -351,18 +351,8 @@
         }
         ArrayMap<View, TransitionValues> endCopy =
                 new ArrayMap<View, TransitionValues>(endValues.viewValues);
-        SparseArray<TransitionValues> endIdCopy =
-                new SparseArray<TransitionValues>(endValues.idValues.size());
-        for (int i = 0; i < endValues.idValues.size(); ++i) {
-            int id = endValues.idValues.keyAt(i);
-            endIdCopy.put(id, endValues.idValues.valueAt(i));
-        }
-        LongSparseArray<TransitionValues> endItemIdCopy =
-                new LongSparseArray<TransitionValues>(endValues.itemIdValues.size());
-        for (int i = 0; i < endValues.itemIdValues.size(); ++i) {
-            long id = endValues.itemIdValues.keyAt(i);
-            endItemIdCopy.put(id, endValues.itemIdValues.valueAt(i));
-        }
+        SparseArray<TransitionValues> endIdCopy = endValues.idValues.clone();
+        LongSparseArray<TransitionValues> endItemIdCopy = endValues.itemIdValues.clone();
         // Walk through the start values, playing everything we find
         // Remove from the end set as we go
         ArrayList<TransitionValues> startValuesList = new ArrayList<TransitionValues>();
@@ -376,21 +366,17 @@
             }
             if (!isInListView) {
                 int id = view.getId();
-                start = startValues.viewValues.get(view) != null ?
-                        startValues.viewValues.get(view) : startValues.idValues.get(id);
-                if (endValues.viewValues.get(view) != null) {
-                    end = endValues.viewValues.get(view);
+                start = startValues.viewValues.get(view);
+                end = endValues.viewValues.get(view);
+                if (end != null) {
                     endCopy.remove(view);
                 } else if (id != View.NO_ID) {
-                    end = endValues.idValues.get(id);
-                    View removeView = null;
-                    for (View viewToRemove : endCopy.keySet()) {
-                        if (viewToRemove.getId() == id) {
-                            removeView = viewToRemove;
-                        }
-                    }
-                    if (removeView != null) {
-                        endCopy.remove(removeView);
+                    end = endIdCopy.get(id);
+                    if (end == null || startValues.viewValues.containsKey(end.view)) {
+                        end = null;
+                        id = View.NO_ID;
+                    } else {
+                        endCopy.remove(end.view);
                     }
                 }
                 endIdCopy.remove(id);
@@ -423,36 +409,16 @@
             }
         }
         // Now walk through the remains of the end set
+        // We've already matched everything from start to end, everything else doesn't match.
         for (View view : endCopy.keySet()) {
             int id = view.getId();
             if (isValidTarget(view, id)) {
-                TransitionValues start = startValues.viewValues.get(view) != null ?
-                        startValues.viewValues.get(view) : startValues.idValues.get(id);
+                TransitionValues start = null;
                 TransitionValues end = endCopy.get(view);
-                endIdCopy.remove(id);
                 startValuesList.add(start);
                 endValuesList.add(end);
             }
         }
-        int endIdCopySize = endIdCopy.size();
-        for (int i = 0; i < endIdCopySize; ++i) {
-            int id = endIdCopy.keyAt(i);
-            if (isValidTarget(null, id)) {
-                TransitionValues start = startValues.idValues.get(id);
-                TransitionValues end = endIdCopy.get(id);
-                startValuesList.add(start);
-                endValuesList.add(end);
-            }
-        }
-        int endItemIdCopySize = endItemIdCopy.size();
-        for (int i = 0; i < endItemIdCopySize; ++i) {
-            long id = endItemIdCopy.keyAt(i);
-            // TODO: Deal with targetIDs and itemIDs
-            TransitionValues start = startValues.itemIdValues.get(id);
-            TransitionValues end = endItemIdCopy.get(id);
-            startValuesList.add(start);
-            endValuesList.add(end);
-        }
         ArrayMap<Animator, AnimationInfo> runningAnimators = getRunningAnimators();
         long minStartDelay = Long.MAX_VALUE;
         int minAnimator = mAnimators.size();
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 11948b2..6c451eb 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -43,7 +43,6 @@
 class GLES20Canvas extends HardwareCanvas {
     // Must match modifiers used in the JNI layer
     private static final int MODIFIER_NONE = 0;
-    private static final int MODIFIER_SHADOW = 1;
     private static final int MODIFIER_SHADER = 2;
 
     private final boolean mOpaque;
@@ -264,27 +263,6 @@
 
     private static native int nCallDrawGLFunction(long renderer, long drawGLFunction);
 
-    @Override
-    public int invokeFunctors(Rect dirty) {
-        return nInvokeFunctors(mRenderer, dirty);
-    }
-
-    private static native int nInvokeFunctors(long renderer, Rect dirty);
-
-    @Override
-    public void detachFunctor(long functor) {
-        nDetachFunctor(mRenderer, functor);
-    }
-
-    private static native void nDetachFunctor(long renderer, long functor);
-
-    @Override
-    public void attachFunctor(long functor) {
-        nAttachFunctor(mRenderer, functor);
-    }
-
-    private static native void nAttachFunctor(long renderer, long functor);
-
     ///////////////////////////////////////////////////////////////////////////
     // Memory
     ///////////////////////////////////////////////////////////////////////////
@@ -1318,12 +1296,6 @@
     private int setupModifiers(Paint paint) {
         int modifiers = MODIFIER_NONE;
 
-        if (paint.hasShadow) {
-            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
-                    paint.shadowColor);
-            modifiers |= MODIFIER_SHADOW;
-        }
-
         final Shader shader = paint.getShader();
         if (shader != null) {
             nSetupShader(mRenderer, shader.native_shader);
@@ -1336,12 +1308,6 @@
     private int setupModifiers(Paint paint, int flags) {
         int modifiers = MODIFIER_NONE;
 
-        if (paint.hasShadow && (flags & MODIFIER_SHADOW) != 0) {
-            nSetupShadow(mRenderer, paint.shadowRadius, paint.shadowDx, paint.shadowDy,
-                    paint.shadowColor);
-            modifiers |= MODIFIER_SHADOW;
-        }
-
         final Shader shader = paint.getShader();
         if (shader != null && (flags & MODIFIER_SHADER) != 0) {
             nSetupShader(mRenderer, shader.native_shader);
@@ -1352,8 +1318,6 @@
     }
 
     private static native void nSetupShader(long renderer, long shader);
-    private static native void nSetupShadow(long renderer, float radius,
-            float dx, float dy, int color);
 
     private static native void nResetModifiers(long renderer, int modifiers);
 }
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 97339cc..7b49006 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -168,7 +168,6 @@
     private final Rect mRedrawClip = new Rect();
 
     private final int[] mSurfaceSize = new int[2];
-    private final FunctorsRunnable mFunctorsRunnable = new FunctorsRunnable();
 
     private long mDrawDelta = Long.MAX_VALUE;
 
@@ -654,6 +653,11 @@
     }
 
     @Override
+    void setOpaque(boolean opaque) {
+        // Not supported
+    }
+
+    @Override
     boolean loadSystemProperties() {
         boolean value;
         boolean changed = false;
@@ -1116,22 +1120,6 @@
         mName = name;
     }
 
-    class FunctorsRunnable implements Runnable {
-        View.AttachInfo attachInfo;
-
-        @Override
-        public void run() {
-            final HardwareRenderer renderer = attachInfo.mHardwareRenderer;
-            if (renderer == null || !renderer.isEnabled() || renderer != GLRenderer.this) {
-                return;
-            }
-
-            if (checkRenderContext() != SURFACE_STATE_ERROR) {
-                mCanvas.invokeFunctors(mRedrawClip);
-            }
-        }
-    }
-
     @Override
     void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks,
             Rect dirty) {
@@ -1366,23 +1354,6 @@
         }
     }
 
-    @Override
-    void detachFunctor(long functor) {
-        if (mCanvas != null) {
-            mCanvas.detachFunctor(functor);
-        }
-    }
-
-    @Override
-    void attachFunctor(View.AttachInfo attachInfo, long functor) {
-        if (mCanvas != null) {
-            mCanvas.attachFunctor(functor);
-            mFunctorsRunnable.attachInfo = attachInfo;
-            attachInfo.mHandler.removeCallbacks(mFunctorsRunnable);
-            attachInfo.mHandler.postDelayed(mFunctorsRunnable,  0);
-        }
-    }
-
     /**
      * Ensures the current EGL context and surface are the ones we expect.
      * This method throws an IllegalStateException if invoked from a thread
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 7ec2cc6..9568760 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -111,45 +111,6 @@
     }
 
     /**
-     * Invoke all the functors who requested to be invoked during the previous frame.
-     *
-     * @param dirty Ignored
-     *
-     * @return Ignored
-     *
-     * @hide
-     */
-    public int invokeFunctors(Rect dirty) {
-        return RenderNode.STATUS_DONE;
-    }
-
-    /**
-     * Detaches the specified functor from the current functor execution queue.
-     *
-     * @param functor The native functor to remove from the execution queue.
-     *
-     * @see #invokeFunctors(android.graphics.Rect)
-     * @see #callDrawGLFunction(long)
-     * @see #detachFunctor(long)
-     *
-     * @hide
-     */
-    abstract void detachFunctor(long functor);
-
-    /**
-     * Attaches the specified functor to the current functor execution queue.
-     *
-     * @param functor The native functor to add to the execution queue.
-     *
-     * @see #invokeFunctors(android.graphics.Rect)
-     * @see #callDrawGLFunction(long)
-     * @see #detachFunctor(long)
-     *
-     * @hide
-     */
-    abstract void attachFunctor(long functor);
-
-    /**
      * Indicates that the specified layer must be updated as soon as possible.
      *
      * @param layer The layer to update
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index d31c79d..e366697 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -423,28 +423,6 @@
     abstract boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap);
 
     /**
-     * Detaches the specified functor from the current functor execution queue.
-     *
-     * @param functor The native functor to remove from the execution queue.
-     *
-     * @see HardwareCanvas#callDrawGLFunction(int)
-     * @see #attachFunctor(android.view.View.AttachInfo, long)
-     */
-    abstract void detachFunctor(long functor);
-
-    /**
-     * Schedules the specified functor in the functors execution queue.
-     *
-     * @param attachInfo AttachInfo tied to this renderer.
-     * @param functor The native functor to insert in the execution queue.
-     *
-     * @see HardwareCanvas#callDrawGLFunction(int)
-     * @see #detachFunctor(long)
-     *
-     */
-    abstract void attachFunctor(View.AttachInfo attachInfo, long functor);
-
-    /**
      * Schedules the functor for execution in either kModeProcess or
      * kModeProcessNoContext, depending on whether or not there is an EGLContext.
      *
@@ -491,6 +469,11 @@
     abstract void setName(String name);
 
     /**
+     * Change the HardwareRenderer's opacity
+     */
+    abstract void setOpaque(boolean opaque);
+
+    /**
      * Creates a hardware renderer using OpenGL.
      *
      * @param translucent True if the surface is translucent, false otherwise
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 05e202b..2d1016a 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1685,10 +1685,6 @@
             case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
             case KeyEvent.KEYCODE_BRIGHTNESS_UP:
             case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
-            case KeyEvent.KEYCODE_DPAD_UP:
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-            case KeyEvent.KEYCODE_DPAD_LEFT:
                 return true;
         }
 
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index a675821..be3b6ce 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -21,6 +21,8 @@
 import android.graphics.Paint;
 import android.util.SparseIntArray;
 
+import com.android.internal.util.VirtualRefBasePtr;
+
 import java.lang.ref.WeakReference;
 
 /**
@@ -70,28 +72,32 @@
     public static final int DELTA_TYPE_DELTA = 1;
 
     private RenderNode mTarget;
-    private long mNativePtr;
+    private VirtualRefBasePtr mNativePtr;
 
     public int mapViewPropertyToRenderProperty(int viewProperty) {
         return sViewPropertyAnimatorMap.get(viewProperty);
     }
 
     public RenderNodeAnimator(int property, int deltaType, float deltaValue) {
-        mNativePtr = nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
-                property, deltaType, deltaValue);
+        init(nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
+                property, deltaType, deltaValue));
     }
 
     public RenderNodeAnimator(CanvasProperty<Float> property, int deltaType, float deltaValue) {
-        mNativePtr = nCreateCanvasPropertyFloatAnimator(
+        init(nCreateCanvasPropertyFloatAnimator(
                 new WeakReference<RenderNodeAnimator>(this),
-                property.getNativeContainer(), deltaType, deltaValue);
+                property.getNativeContainer(), deltaType, deltaValue));
     }
 
     public RenderNodeAnimator(CanvasProperty<Paint> property, int paintField,
             int deltaType, float deltaValue) {
-        mNativePtr = nCreateCanvasPropertyPaintAnimator(
+        init(nCreateCanvasPropertyPaintAnimator(
                 new WeakReference<RenderNodeAnimator>(this),
-                property.getNativeContainer(), paintField, deltaType, deltaValue);
+                property.getNativeContainer(), paintField, deltaType, deltaValue));
+    }
+
+    private void init(long ptr) {
+        mNativePtr = new VirtualRefBasePtr(ptr);
     }
 
     public void start(View target) {
@@ -115,11 +121,11 @@
     }
 
     public void setDuration(int duration) {
-        nSetDuration(mNativePtr, duration);
+        nSetDuration(mNativePtr.get(), duration);
     }
 
     long getNativeAnimator() {
-        return mNativePtr;
+        return mNativePtr.get();
     }
 
     private void onFinished() {
@@ -134,16 +140,6 @@
         }
     }
 
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            nUnref(mNativePtr);
-            mNativePtr = 0;
-        } finally {
-            super.finalize();
-        }
-    }
-
     private static native long nCreateAnimator(WeakReference<RenderNodeAnimator> weakThis,
             int property, int deltaValueType, float deltaValue);
     private static native long nCreateCanvasPropertyFloatAnimator(WeakReference<RenderNodeAnimator> weakThis,
@@ -151,5 +147,4 @@
     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 void nUnref(long nativePtr);
 }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 0bf99d3..2587ba1 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -148,6 +148,11 @@
     }
 
     @Override
+    void setOpaque(boolean opaque) {
+        nSetOpaque(mNativeProxy, opaque);
+    }
+
+    @Override
     int getWidth() {
         return mWidth;
     }
@@ -215,16 +220,6 @@
     }
 
     @Override
-    void detachFunctor(long functor) {
-        // no-op, we never attach functors to need to detach them
-    }
-
-    @Override
-    void attachFunctor(AttachInfo attachInfo, long functor) {
-        invokeFunctor(functor, true);
-    }
-
-    @Override
     void invokeFunctor(long functor, boolean waitForCompletion) {
         nInvokeFunctor(mNativeProxy, functor, waitForCompletion);
     }
@@ -312,6 +307,7 @@
     private static native void nUpdateSurface(long nativeProxy, Surface window);
     private static native void nPauseSurface(long nativeProxy, Surface window);
     private static native void nSetup(long nativeProxy, int width, int height);
+    private static native void nSetOpaque(long nativeProxy, boolean opaque);
     private static native void nSetDisplayListData(long nativeProxy, long displayList,
             long newData);
     private static native int nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos,
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d8fcfc5..bef96b1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,7 +16,9 @@
 
 package android.view;
 
+import android.animation.AnimatorInflater;
 import android.animation.RevealAnimator;
+import android.animation.StateListAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -667,6 +669,7 @@
  * @attr ref android.R.styleable#View_scrollbarTrackVertical
  * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack
  * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
+ * @attr ref android.R.styleable#View_stateListAnimator
  * @attr ref android.R.styleable#View_sharedElementName
  * @attr ref android.R.styleable#View_soundEffectsEnabled
  * @attr ref android.R.styleable#View_tag
@@ -3258,6 +3261,11 @@
     private Outline mOutline;
 
     /**
+     * Animator that automatically runs based on state changes.
+     */
+    private StateListAnimator mStateListAnimator;
+
+    /**
      * When this view has focus and the next focus is {@link #FOCUS_LEFT},
      * the user may specify which view to go to next.
      */
@@ -3995,6 +4003,10 @@
                 case R.styleable.View_nestedScrollingEnabled:
                     setNestedScrollingEnabled(a.getBoolean(attr, false));
                     break;
+                case R.styleable.View_stateListAnimator:
+                    setStateListAnimator(AnimatorInflater.loadStateListAnimator(context,
+                            a.getResourceId(attr, 0)));
+                    break;
             }
         }
 
@@ -10620,6 +10632,40 @@
     }
 
     /**
+     * Returns the current StateListAnimator if exists.
+     *
+     * @return StateListAnimator or null if it does not exists
+     * @see    #setStateListAnimator(android.animation.StateListAnimator)
+     */
+    public StateListAnimator getStateListAnimator() {
+        return mStateListAnimator;
+    }
+
+    /**
+     * Attaches the provided StateListAnimator to this View.
+     * <p>
+     * Any previously attached StateListAnimator will be detached.
+     *
+     * @param stateListAnimator The StateListAnimator to update the view
+     * @see {@link android.animation.StateListAnimator}
+     */
+    public void setStateListAnimator(StateListAnimator stateListAnimator) {
+        if (mStateListAnimator == stateListAnimator) {
+            return;
+        }
+        if (mStateListAnimator != null) {
+            mStateListAnimator.setTarget(null);
+        }
+        mStateListAnimator = stateListAnimator;
+        if (stateListAnimator != null) {
+            stateListAnimator.setTarget(this);
+            if (isAttachedToWindow()) {
+                stateListAnimator.setState(getDrawableState());
+            }
+        }
+    }
+
+    /**
      * Sets the outline of the view, which defines the shape of the shadow it
      * casts.
      * <p>
@@ -12835,7 +12881,6 @@
         destroyLayer(false);
 
         cleanupDraw();
-
         mCurrentAnimation = null;
     }
 
@@ -15489,9 +15534,11 @@
     /**
      * This function is called whenever the state of the view changes in such
      * a way that it impacts the state of drawables being shown.
-     *
-     * <p>Be sure to call through to the superclass when overriding this
-     * function.
+     * <p>
+     * If the View has a StateListAnimator, it will also be called to run necessary state
+     * change animations.
+     * <p>
+     * Be sure to call through to the superclass when overriding this function.
      *
      * @see Drawable#setState(int[])
      */
@@ -15500,6 +15547,10 @@
         if (d != null && d.isStateful()) {
             d.setState(getDrawableState());
         }
+
+        if (mStateListAnimator != null) {
+            mStateListAnimator.setState(getDrawableState());
+        }
     }
 
     /**
@@ -15644,11 +15695,17 @@
     /**
      * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()}
      * on all Drawable objects associated with this view.
+     * <p>
+     * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator
+     * attached to this view.
      */
     public void jumpDrawablesToCurrentState() {
         if (mBackground != null) {
             mBackground.jumpToCurrentState();
         }
+        if (mStateListAnimator != null) {
+            mStateListAnimator.jumpToCurrentState();
+        }
     }
 
     /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index db87394..9b09d85 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -665,18 +665,9 @@
         mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_FLUSH_LAYER_UPDATES));
     }
 
-    public void attachFunctor(long functor) {
-        //noinspection SimplifiableIfStatement
-        if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
-            mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
-        }
-    }
-
     public void detachFunctor(long functor) {
+        // TODO: Make the resize buffer some other way to not need this block
         mBlockResizeBuffer = true;
-        if (mAttachInfo.mHardwareRenderer != null) {
-            mAttachInfo.mHardwareRenderer.detachFunctor(functor);
-        }
     }
 
     public boolean invokeFunctor(long functor, boolean waitForCompletion) {
@@ -719,12 +710,15 @@
 
             if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
                     && forceHwAccelerated)) {
-                // Don't enable hardware acceleration when we're not on the main thread
-                if (!HardwareRenderer.sSystemRendererDisabled &&
-                        Looper.getMainLooper() != Looper.myLooper()) {
-                    Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
-                            + "acceleration outside of the main thread, aborting");
-                    return;
+                if (!HardwareRenderer.sUseRenderThread) {
+                    // TODO: Delete
+                    // Don't enable hardware acceleration when we're not on the main thread
+                    if (!HardwareRenderer.sSystemRendererDisabled &&
+                            Looper.getMainLooper() != Looper.myLooper()) {
+                        Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+                                + "acceleration outside of the main thread, aborting");
+                        return;
+                    }
                 }
 
                 if (mAttachInfo.mHardwareRenderer != null) {
@@ -6174,8 +6168,10 @@
     }
 
     void changeCanvasOpacity(boolean opaque) {
-        // TODO(romainguy): recreate Canvas (software or hardware) to reflect the opacity change.
         Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
+        if (mAttachInfo.mHardwareRenderer != null) {
+            mAttachInfo.mHardwareRenderer.setOpaque(opaque);
+        }
     }
 
     class TakenSurfaceHolder extends BaseSurfaceHolder {
diff --git a/core/java/android/view/inputmethod/CorrectionInfo.java b/core/java/android/view/inputmethod/CorrectionInfo.java
index 1b04e49..a43dfe8 100644
--- a/core/java/android/view/inputmethod/CorrectionInfo.java
+++ b/core/java/android/view/inputmethod/CorrectionInfo.java
@@ -88,16 +88,15 @@
     /**
      * Used to make this class parcelable.
      */
-    public static final Parcelable.Creator<CorrectionInfo> CREATOR
-            = new Parcelable.Creator<CorrectionInfo>() {
-        public CorrectionInfo createFromParcel(Parcel source) {
-            return new CorrectionInfo(source);
-        }
-
-        public CorrectionInfo[] newArray(int size) {
-            return new CorrectionInfo[size];
-        }
-    };
+    public static final Parcelable.Creator<CorrectionInfo> CREATOR =
+            new Parcelable.Creator<CorrectionInfo>() {
+                public CorrectionInfo createFromParcel(Parcel source) {
+                    return new CorrectionInfo(source);
+                }
+                public CorrectionInfo[] newArray(int size) {
+                    return new CorrectionInfo[size];
+                }
+            };
 
     public int describeContents() {
         return 0;
diff --git a/core/res/res/drawable/stat_sys_adb.xml b/core/java/android/view/inputmethod/CursorAnchorInfo.aidl
similarity index 61%
copy from core/res/res/drawable/stat_sys_adb.xml
copy to core/java/android/view/inputmethod/CursorAnchorInfo.aidl
index dfc8563..2ee9edb 100644
--- a/core/res/res/drawable/stat_sys_adb.xml
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.aidl
@@ -1,13 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
 /*
- * Copyright 2013, 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.
  * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ *      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,
@@ -15,9 +13,7 @@
  * 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/stat_sys_adb_am"
-        android:autoMirrored="true">
-</bitmap>
+package android.view.inputmethod;
+
+parcelable CursorAnchorInfo;
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
new file mode 100644
index 0000000..92455df
--- /dev/null
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -0,0 +1,449 @@
+/*
+ * 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.view.inputmethod;
+
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.Layout;
+import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder;
+
+import java.util.Objects;
+
+/**
+ * Positional information about the text insertion point and characters in the composition string.
+ *
+ * <p>This class encapsulates locations of the text insertion point and the composition string in
+ * the screen coordinates so that IMEs can render their UI components near where the text is
+ * actually inserted.</p>
+ */
+public final class CursorAnchorInfo implements Parcelable {
+    private final int mSelectionStart;
+    private final int mSelectionEnd;
+    private final int mCandidatesStart;
+    private final int mCandidatesEnd;
+
+    /**
+     * Horizontal position of the insertion marker, in the local coordinates that will be
+     * transformed with the transformation matrix when rendered on the screen. This should be
+     * calculated or compatible with {@link Layout#getPrimaryHorizontal(int)}. This can be
+     * {@code java.lang.Float.NaN} when no value is specified.
+     */
+    private final float mInsertionMarkerHorizontal;
+    /**
+     * Vertical position of the insertion marker, in the local coordinates that will be
+     * transformed with the transformation matrix when rendered on the screen. This should be
+     * calculated or compatible with {@link Layout#getLineTop(int)}. This can be
+     * {@code java.lang.Float.NaN} when no value is specified.
+     */
+    private final float mInsertionMarkerTop;
+    /**
+     * Vertical position of the insertion marker, in the local coordinates that will be
+     * transformed with the transformation matrix when rendered on the screen. This should be
+     * calculated or compatible with {@link Layout#getLineBaseline(int)}. This can be
+     * {@code java.lang.Float.NaN} when no value is specified.
+     */
+    private final float mInsertionMarkerBaseline;
+    /**
+     * Vertical position of the insertion marker, in the local coordinates that will be
+     * transformed with the transformation matrix when rendered on the screen. This should be
+     * calculated or compatible with {@link Layout#getLineBottom(int)}. This can be
+     * {@code java.lang.Float.NaN} when no value is specified.
+     */
+    private final float mInsertionMarkerBottom;
+
+    /**
+     * Container of rectangular position of characters, keyed with character index in a unit of
+     * Java chars, in the local coordinates that will be transformed with the transformation matrix
+     * when rendered on the screen.
+     */
+    private final SparseRectFArray mCharacterRects;
+
+    /**
+     * Transformation matrix that is applied to any positional information of this class to
+     * transform local coordinates into screen coordinates.
+     */
+    private final Matrix mMatrix;
+
+    public CursorAnchorInfo(final Parcel source) {
+        mSelectionStart = source.readInt();
+        mSelectionEnd = source.readInt();
+        mCandidatesStart = source.readInt();
+        mCandidatesEnd = source.readInt();
+        mInsertionMarkerHorizontal = source.readFloat();
+        mInsertionMarkerTop = source.readFloat();
+        mInsertionMarkerBaseline = source.readFloat();
+        mInsertionMarkerBottom = source.readFloat();
+        mCharacterRects = source.readParcelable(SparseRectFArray.class.getClassLoader());
+        mMatrix = new Matrix();
+        mMatrix.setValues(source.createFloatArray());
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mSelectionStart);
+        dest.writeInt(mSelectionEnd);
+        dest.writeInt(mCandidatesStart);
+        dest.writeInt(mCandidatesEnd);
+        dest.writeFloat(mInsertionMarkerHorizontal);
+        dest.writeFloat(mInsertionMarkerTop);
+        dest.writeFloat(mInsertionMarkerBaseline);
+        dest.writeFloat(mInsertionMarkerBottom);
+        dest.writeParcelable(mCharacterRects, flags);
+        final float[] matrixArray = new float[9];
+        mMatrix.getValues(matrixArray);
+        dest.writeFloatArray(matrixArray);
+    }
+
+    @Override
+    public int hashCode(){
+        // TODO: Improve the hash function.
+        final float floatHash = mSelectionStart + mSelectionEnd + mCandidatesStart + mCandidatesEnd
+                + mInsertionMarkerHorizontal + mInsertionMarkerTop + mInsertionMarkerBaseline
+                + mInsertionMarkerBottom;
+        int hash = floatHash > 0 ? (int) floatHash : (int)(-floatHash);
+        if (mCharacterRects != null) {
+            hash += mCharacterRects.hashCode();
+        }
+        hash += mMatrix.hashCode();
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj){
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof CursorAnchorInfo)) {
+            return false;
+        }
+        final CursorAnchorInfo that = (CursorAnchorInfo) obj;
+        if (hashCode() != that.hashCode()) {
+            return false;
+        }
+        if (mSelectionStart != that.mSelectionStart
+                || mSelectionEnd != that.mSelectionEnd
+                || mCandidatesStart != that.mCandidatesStart
+                || mCandidatesEnd != that.mCandidatesEnd) {
+            return false;
+        }
+        if (!Objects.equals(mCharacterRects, that.mCharacterRects)) {
+            return false;
+        }
+        if (!Objects.equals(mMatrix, that.mMatrix)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "SelectionInfo{mSelection=" + mSelectionStart + "," + mSelectionEnd
+                + " mCandiadtes=" + mCandidatesStart + "," + mCandidatesEnd
+                + " mInsertionMarkerHorizontal=" + mInsertionMarkerHorizontal
+                + " mInsertionMarkerTop=" + mInsertionMarkerTop
+                + " mInsertionMarkerBaseline=" + mInsertionMarkerBaseline
+                + " mInsertionMarkerBottom=" + mInsertionMarkerBottom
+                + " mCharacterRects=" + (mCharacterRects != null ? mCharacterRects : "null")
+                + " mMatrix=" + mMatrix
+                + "}";
+    }
+
+    /**
+     * Builder for {@link CursorAnchorInfo}. This class is not designed to be thread-safe.
+     */
+    public static final class CursorAnchorInfoBuilder {
+        /**
+         * Sets the text range of the selection. Calling this can be skipped if there is no
+         * selection.
+         */
+        public CursorAnchorInfoBuilder setSelectionRange(final int newStart, final int newEnd) {
+            mSelectionStart = newStart;
+            mSelectionEnd = newEnd;
+            return this;
+        }
+        private int mSelectionStart = -1;
+        private int mSelectionEnd = -1;
+
+        /**
+         * Sets the text range of the composition string. Calling this can be skipped if there is
+         * no composition.
+         */
+        public CursorAnchorInfoBuilder setCandidateRange(final int start, final int end) {
+            mCandidateStart = start;
+            mCandidateEnd = end;
+            return this;
+        }
+        private int mCandidateStart = -1;
+        private int mCandidateEnd = -1;
+
+        /**
+         * Sets the location of the text insertion point (zero width cursor) as a rectangle in
+         * local coordinates. Calling this can be skipped when there is no text insertion point;
+         * however if there is an insertion point, editors must call this method.
+         * @param horizontalPosition horizontal position of the insertion marker, in the local
+         * coordinates that will be transformed with the transformation matrix when rendered on the
+         * screen. This should be calculated or compatible with
+         * {@link Layout#getPrimaryHorizontal(int)}.
+         * @param lineTop vertical position of the insertion marker, in the local coordinates that
+         * will be transformed with the transformation matrix when rendered on the screen. This
+         * should be calculated or compatible with {@link Layout#getLineTop(int)}.
+         * @param lineBaseline vertical position of the insertion marker, in the local coordinates
+         * that will be transformed with the transformation matrix when rendered on the screen. This
+         * should be calculated or compatible with {@link Layout#getLineBaseline(int)}.
+         * @param lineBottom vertical position of the insertion marker, in the local coordinates
+         * that will be transformed with the transformation matrix when rendered on the screen. This
+         * should be calculated or compatible with {@link Layout#getLineBottom(int)}.
+         */
+        public CursorAnchorInfoBuilder setInsertionMarkerLocation(
+                final float horizontalPosition, final float lineTop, final float lineBaseline,
+                final float lineBottom){
+            mInsertionMarkerHorizontal = horizontalPosition;
+            mInsertionMarkerTop = lineTop;
+            mInsertionMarkerBaseline = lineBaseline;
+            mInsertionMarkerBottom = lineBottom;
+            return this;
+        }
+        private float mInsertionMarkerHorizontal = Float.NaN;
+        private float mInsertionMarkerTop = Float.NaN;
+        private float mInsertionMarkerBaseline = Float.NaN;
+        private float mInsertionMarkerBottom = Float.NaN;
+
+        /**
+         * Adds the bounding box of the character specified with the index.
+         * <p>
+         * Editor authors should not call this method for characters that are invisible.
+         * </p>
+         *
+         * @param index index of the character in Java chars units. Must be specified in
+         * ascending order across successive calls.
+         * @param leadingEdgeX x coordinate of the leading edge of the character in local
+         * coordinates, that is, left edge for LTR text and right edge for RTL text.
+         * @param leadingEdgeY y coordinate of the leading edge of the character in local
+         * coordinates.
+         * @param trailingEdgeX x coordinate of the trailing edge of the character in local
+         * coordinates, that is, right edge for LTR text and left edge for RTL text.
+         * @param trailingEdgeY y coordinate of the trailing edge of the character in local
+         * coordinates.
+         * @throws IllegalArgumentException If the index is a negative value, or not greater than
+         * all of the previously called indices.
+         */
+        public CursorAnchorInfoBuilder addCharacterRect(final int index,
+                final float leadingEdgeX, final float leadingEdgeY, final float trailingEdgeX,
+                final float trailingEdgeY) {
+            if (index < 0) {
+                throw new IllegalArgumentException("index must not be a negative integer.");
+            }
+            if (mCharacterRectBuilder == null) {
+                mCharacterRectBuilder = new SparseRectFArrayBuilder();
+            }
+            mCharacterRectBuilder.append(index, leadingEdgeX, leadingEdgeY, trailingEdgeX,
+                    trailingEdgeY);
+            return this;
+        }
+        private SparseRectFArrayBuilder mCharacterRectBuilder = null;
+
+        /**
+         * Sets the matrix that transforms local coordinates into screen coordinates.
+         * @param matrix transformation matrix from local coordinates into screen coordinates. null
+         * is interpreted as an identity matrix.
+         */
+        public CursorAnchorInfoBuilder setMatrix(final Matrix matrix) {
+            if (matrix != null) {
+                mMatrix = matrix;
+            } else {
+                mMatrix = Matrix.IDENTITY_MATRIX;
+            }
+            return this;
+        }
+        private Matrix mMatrix = Matrix.IDENTITY_MATRIX;
+
+        /**
+         * @return {@link CursorAnchorInfo} using parameters in this
+         * {@link CursorAnchorInfoBuilder}.
+         */
+        public CursorAnchorInfo build() {
+            return new CursorAnchorInfo(this);
+        }
+
+        /**
+         * Resets the internal state so that this instance can be reused to build another
+         * instance of {@link CursorAnchorInfo}.
+         */
+        public void reset() {
+            mSelectionStart = -1;
+            mSelectionEnd = -1;
+            mCandidateStart = -1;
+            mCandidateEnd = -1;
+            mInsertionMarkerHorizontal = Float.NaN;
+            mInsertionMarkerTop = Float.NaN;
+            mInsertionMarkerBaseline = Float.NaN;
+            mInsertionMarkerBottom = Float.NaN;
+            mMatrix = Matrix.IDENTITY_MATRIX;
+            if (mCharacterRectBuilder != null) {
+                mCharacterRectBuilder.reset();
+            }
+        }
+    }
+
+    private CursorAnchorInfo(final CursorAnchorInfoBuilder builder) {
+        mSelectionStart = builder.mSelectionStart;
+        mSelectionEnd = builder.mSelectionEnd;
+        mCandidatesStart = builder.mCandidateStart;
+        mCandidatesEnd = builder.mCandidateEnd;
+        mInsertionMarkerHorizontal = builder.mInsertionMarkerHorizontal;
+        mInsertionMarkerTop = builder.mInsertionMarkerTop;
+        mInsertionMarkerBaseline = builder.mInsertionMarkerBaseline;
+        mInsertionMarkerBottom = builder.mInsertionMarkerBottom;
+        mCharacterRects = builder.mCharacterRectBuilder != null ?
+                builder.mCharacterRectBuilder.build() : null;
+        mMatrix = builder.mMatrix;
+    }
+
+    /**
+     * Returns the index where the selection starts.
+     * @return -1 if there is no selection.
+     */
+    public int getSelectionStart() {
+        return mSelectionStart;
+    }
+
+    /**
+     * Returns the index where the selection ends.
+     * @return -1 if there is no selection.
+     */
+    public int getSelectionEnd() {
+        return mSelectionEnd;
+    }
+
+    /**
+     * Returns the index where the composition starts.
+     * @return -1 if there is no composition.
+     */
+    public int getCandidatesStart() {
+        return mCandidatesStart;
+    }
+
+    /**
+     * Returns the index where the composition ends.
+     * @return -1 if there is no composition.
+     */
+    public int getCandidatesEnd() {
+        return mCandidatesEnd;
+    }
+
+    /**
+     * Returns the horizontal start of the insertion marker, in the local coordinates that will
+     * be transformed with {@link #getMatrix()} when rendered on the screen.
+     * @return x coordinate that is compatible with {@link Layout#getPrimaryHorizontal(int)}.
+     * Pay special care to RTL/LTR handling.
+     * {@code java.lang.Float.NaN} if not specified.
+     * @see Layout#getPrimaryHorizontal(int)
+     */
+    public float getInsertionMarkerHorizontal() {
+        return mInsertionMarkerHorizontal;
+    }
+    /**
+     * Returns the vertical top position of the insertion marker, in the local coordinates that
+     * will be transformed with {@link #getMatrix()} when rendered on the screen.
+     * @return y coordinate that is compatible with {@link Layout#getLineTop(int)}.
+     * {@code java.lang.Float.NaN} if not specified.
+     */
+    public float getInsertionMarkerTop() {
+        return mInsertionMarkerTop;
+    }
+    /**
+     * Returns the vertical baseline position of the insertion marker, in the local coordinates
+     * that will be transformed with {@link #getMatrix()} when rendered on the screen.
+     * @return y coordinate that is compatible with {@link Layout#getLineBaseline(int)}.
+     * {@code java.lang.Float.NaN} if not specified.
+     */
+    public float getInsertionMarkerBaseline() {
+        return mInsertionMarkerBaseline;
+    }
+    /**
+     * Returns the vertical bottom position of the insertion marker, in the local coordinates
+     * that will be transformed with {@link #getMatrix()} when rendered on the screen.
+     * @return y coordinate that is compatible with {@link Layout#getLineBottom(int)}.
+     * {@code java.lang.Float.NaN} if not specified.
+     */
+    public float getInsertionMarkerBottom() {
+        return mInsertionMarkerBottom;
+    }
+
+    /**
+     * Returns a new instance of {@link RectF} that indicates the location of the character
+     * specified with the index.
+     * <p>
+     * Note that coordinates are not necessarily contiguous or even monotonous, especially when
+     * RTL text and LTR text are mixed.
+     * </p>
+     * @param index index of the character in a Java chars.
+     * @return a new instance of {@link RectF} that represents the location of the character in
+     * local coordinates. null if the character is invisible or the application did not provide
+     * the location. Note that the {@code left} field can be greater than the {@code right} field
+     * if the character is in RTL text.
+     */
+    // TODO: Prepare a document about the expected behavior for surrogate pairs, combining
+    // characters, and non-graphical chars.
+    public RectF getCharacterRect(final int index) {
+        if (mCharacterRects == null) {
+            return null;
+        }
+        return mCharacterRects.get(index);
+    }
+
+    /**
+     * Returns a new instance of {@link android.graphics.Matrix} that indicates the transformation
+     * matrix that is to be applied other positional data in this class.
+     * @return a new instance (copy) of the transformation matrix.
+     */
+    public Matrix getMatrix() {
+        return new Matrix(mMatrix);
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<CursorAnchorInfo> CREATOR
+            = new Parcelable.Creator<CursorAnchorInfo>() {
+        @Override
+        public CursorAnchorInfo createFromParcel(Parcel source) {
+            return new CursorAnchorInfo(source);
+        }
+
+        @Override
+        public CursorAnchorInfo[] newArray(int size) {
+            return new CursorAnchorInfo[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 0227873..e1c6f52 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -49,6 +49,7 @@
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewRootImpl;
+import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -321,6 +322,7 @@
      * The buffer to retrieve the view location in screen coordinates in {@link #updateCursor}.
      */
     private final int[] mViewTopLeft = new int[2];
+    private final CursorAnchorInfoBuilder mCursorAnchorInfoBuilder = new CursorAnchorInfoBuilder();
 
     // -----------------------------------------------------------
     
@@ -1435,7 +1437,7 @@
                     || mCurrentTextBoxAttribute == null || mCurMethod == null) {
                 return;
             }
-            
+
             if (mCursorSelStart != selStart || mCursorSelEnd != selEnd
                     || mCursorCandStart != candidatesStart
                     || mCursorCandEnd != candidatesEnd) {
@@ -1556,6 +1558,31 @@
     }
 
     /**
+     * Report positional change of the text insertion point and/or characters in the composition
+     * string.
+     */
+    public void updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo) {
+        if (view == null || cursorAnchorInfo == null) {
+            return;
+        }
+        checkFocus();
+        synchronized (mH) {
+            if ((mServedView != view &&
+                    (mServedView == null || !mServedView.checkInputConnectionProxy(view)))
+                    || mCurrentTextBoxAttribute == null || mCurMethod == null) {
+                return;
+            }
+            if (DEBUG) Log.d(TAG, "updateCursorAnchorInfo");
+
+            try {
+                mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo);
+            } catch (RemoteException e) {
+                Log.w(TAG, "IME died: " + mCurId, e);
+            }
+        }
+    }
+
+    /**
      * Call {@link InputMethodSession#appPrivateCommand(String, Bundle)
      * InputMethodSession.appPrivateCommand()} on the current Input Method.
      * @param view Optional View that is sending the command, or null if
diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java
index 6386299..74fbbc7 100644
--- a/core/java/android/view/inputmethod/InputMethodSession.java
+++ b/core/java/android/view/inputmethod/InputMethodSession.java
@@ -165,7 +165,7 @@
     public void appPrivateCommand(String action, Bundle data);
     
     /**
-     * Toggle the soft input window. 
+     * Toggle the soft input window.
      * Applications can toggle the state of the soft input window.
      * @param showFlags Provides additional operating flags.  May be
      * 0 or have the {@link InputMethodManager#SHOW_IMPLICIT},
@@ -175,4 +175,14 @@
      * {@link  InputMethodManager#HIDE_NOT_ALWAYS} bit set.
      */
     public void toggleSoftInput(int showFlags, int hideFlags);
+
+    /**
+     * This method is called when the cursor and/or the character position relevant to text input
+     * is changed on the screen.  This is not called by default.  It will only be reported if
+     * requested by the input method.
+     *
+     * @param cursorAnchorInfo Positional information relevant to text input, such as text
+     * insertion point and composition string.
+     */
+    public void updateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo);
 }
diff --git a/core/java/android/view/inputmethod/SparseRectFArray.java b/core/java/android/view/inputmethod/SparseRectFArray.java
new file mode 100644
index 0000000..40cade7
--- /dev/null
+++ b/core/java/android/view/inputmethod/SparseRectFArray.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 android.view.inputmethod;
+
+import android.graphics.RectF;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * An implementation of SparseArray specialized for {@link android.graphics.RectF}.
+ * <p>
+ * As this is a sparse array, it represents an array of {@link RectF} most of which are null. This
+ * class could be in some other packages like android.graphics or android.util but currently
+ * belong to android.view.inputmethod because this class is hidden and used only in input method
+ * framework.
+ * </p>
+ * @hide
+ */
+public final class SparseRectFArray implements Parcelable {
+    /**
+     * The keys, in ascending order, of those {@link RectF} that are not null. For example,
+     * {@code [null, null, null, Rect1, null, Rect2]} would be represented by {@code [3,5]}.
+     * @see #mCoordinates
+     */
+    private final int[] mKeys;
+
+    /**
+     * Stores coordinates of the rectangles, in the order of
+     * {@code rects[mKeys[0]].left}, {@code rects[mKeys[0]].top},
+     * {@code rects[mKeys[0]].right}, {@code rects[mKeys[0]].bottom},
+     * {@code rects[mKeys[1]].left}, {@code rects[mKeys[1]].top},
+     * {@code rects[mKeys[1]].right}, {@code rects[mKeys[1]].bottom},
+     * {@code rects[mKeys[2]].left}, {@code rects[mKeys[2]].top}, ....
+     */
+    private final float[] mCoordinates;
+
+    public SparseRectFArray(final Parcel source) {
+        mKeys = source.createIntArray();
+        mCoordinates = source.createFloatArray();
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeIntArray(mKeys);
+        dest.writeFloatArray(mCoordinates);
+    }
+
+    @Override
+    public int hashCode() {
+        // TODO: Improve the hash function.
+        if (mKeys == null || mKeys.length == 0) {
+            return 0;
+        }
+        int hash = mKeys.length;
+        // For performance reasons, only the first rectangle is used for the hash code now.
+        for (int i = 0; i < 4; i++) {
+            hash *= 31;
+            hash += mCoordinates[i];
+        }
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj){
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof SparseRectFArray)) {
+            return false;
+        }
+        final SparseRectFArray that = (SparseRectFArray) obj;
+
+        return Arrays.equals(mKeys, that.mKeys) && Arrays.equals(mCoordinates, that.mCoordinates);
+    }
+
+    @Override
+    public String toString() {
+        if (mKeys == null || mCoordinates == null) {
+            return "SparseRectFArray{}";
+        }
+        final StringBuilder sb = new StringBuilder();
+        sb.append("SparseRectFArray{");
+        for (int i = 0; i < mKeys.length; i++) {
+            if (i != 0) {
+                sb.append(", ");
+            }
+            final int baseIndex = i * 4;
+            sb.append(mKeys[i]);
+            sb.append(":[");
+            sb.append(mCoordinates[baseIndex + 0]);
+            sb.append(",");
+            sb.append(mCoordinates[baseIndex + 1]);
+            sb.append("],[");
+            sb.append(mCoordinates[baseIndex + 2]);
+            sb.append(",");
+            sb.append(mCoordinates[baseIndex + 3]);
+            sb.append("]");
+        }
+        sb.append("}");
+        return sb.toString();
+    }
+
+    /**
+     * Builder for {@link SparseRectFArray}. This class is not designed to be thread-safe.
+     * @hide
+     */
+    public static final class SparseRectFArrayBuilder {
+        /**
+         * Throws {@link IllegalArgumentException} to make sure that this class is correctly used.
+         * @param key key to be checked.
+         */
+        private void checkIndex(final int key) {
+            if (mCount == 0) {
+                return;
+            }
+            if (mKeys[mCount - 1] >= key) {
+                throw new IllegalArgumentException("key must be greater than all existing keys.");
+            }
+        }
+
+        /**
+         * Extends the internal array if necessary.
+         */
+        private void ensureBufferSize() {
+            if (mKeys == null) {
+                mKeys = new int[INITIAL_SIZE];
+            }
+            if (mCoordinates == null) {
+                mCoordinates = new float[INITIAL_SIZE * 4];
+            }
+            final int requiredIndexArraySize = mCount + 1;
+            if (mKeys.length <= requiredIndexArraySize) {
+                final int[] newArray = new int[requiredIndexArraySize * 2];
+                System.arraycopy(mKeys, 0, newArray, 0, mCount);
+                mKeys = newArray;
+            }
+            final int requiredCoordinatesArraySize = (mCount + 1) * 4;
+            if (mCoordinates.length <= requiredCoordinatesArraySize) {
+                final float[] newArray = new float[requiredCoordinatesArraySize * 2];
+                System.arraycopy(mCoordinates, 0, newArray, 0, mCount * 4);
+                mCoordinates = newArray;
+            }
+        }
+
+        /**
+         * Puts the rectangle with an integer key.
+         * @param key the key to be associated with the rectangle. It must be greater than all
+         * existing keys that have been previously specified.
+         * @param left left of the rectangle.
+         * @param top top of the rectangle.
+         * @param right right of the rectangle.
+         * @param bottom bottom of the rectangle.
+         * @return the receiver object itself for chaining method calls.
+         * @throws IllegalArgumentException If the index is not greater than all of existing keys.
+         */
+        public SparseRectFArrayBuilder append(final int key,
+                final float left, final float top, final float right, final float bottom) {
+            checkIndex(key);
+            ensureBufferSize();
+            final int baseCoordinatesIndex = mCount * 4;
+            mCoordinates[baseCoordinatesIndex + 0] = left;
+            mCoordinates[baseCoordinatesIndex + 1] = top;
+            mCoordinates[baseCoordinatesIndex + 2] = right;
+            mCoordinates[baseCoordinatesIndex + 3] = bottom;
+            mKeys[mCount] = key;
+            ++mCount;
+            return this;
+        }
+        private int mCount = 0;
+        private int[] mKeys = null;
+        private float[] mCoordinates = null;
+        private static int INITIAL_SIZE = 16;
+
+        /**
+         * @return {@link SparseRectFArray} using parameters in this {@link SparseRectFArray}.
+         */
+        public SparseRectFArray build() {
+            return new SparseRectFArray(this);
+        }
+
+        public void reset() {
+            if (mCount == 0) {
+                mKeys = null;
+                mCoordinates = null;
+            }
+            mCount = 0;
+        }
+    }
+
+    private SparseRectFArray(final SparseRectFArrayBuilder builder) {
+        if (builder.mCount == 0) {
+            mKeys = null;
+            mCoordinates = null;
+        } else {
+            mKeys = new int[builder.mCount];
+            mCoordinates = new float[builder.mCount * 4];
+            System.arraycopy(builder.mKeys, 0, mKeys, 0, builder.mCount);
+            System.arraycopy(builder.mCoordinates, 0, mCoordinates, 0, builder.mCount * 4);
+        }
+    }
+
+    public RectF get(final int index) {
+        if (mKeys == null) {
+            return null;
+        }
+        if (index < 0) {
+            return null;
+        }
+        final int arrayIndex = Arrays.binarySearch(mKeys, index);
+        if (arrayIndex < 0) {
+            return null;
+        }
+        final int baseCoordIndex = arrayIndex * 4;
+        return new RectF(mCoordinates[baseCoordIndex],
+                mCoordinates[baseCoordIndex + 1],
+                mCoordinates[baseCoordIndex + 2],
+                mCoordinates[baseCoordIndex + 3]);
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<SparseRectFArray> CREATOR =
+            new Parcelable.Creator<SparseRectFArray>() {
+                @Override
+                public SparseRectFArray createFromParcel(Parcel source) {
+                    return new SparseRectFArray(source);
+                }
+                @Override
+                public SparseRectFArray[] newArray(int size) {
+                    return new SparseRectFArray[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
+
diff --git a/core/java/android/webkit/EventLogTags.logtags b/core/java/android/webkit/EventLogTags.logtags
index b0b5493..a90aebd 100644
--- a/core/java/android/webkit/EventLogTags.logtags
+++ b/core/java/android/webkit/EventLogTags.logtags
@@ -8,3 +8,4 @@
 # 70103- used by the browser app itself
 
 70150 browser_snap_center
+70151 exp_det_attempt_to_call_object_getclass (app_signature|3)
diff --git a/core/java/android/webkit/PermissionRequest.java b/core/java/android/webkit/PermissionRequest.java
index 3e33498..fa760b7 100644
--- a/core/java/android/webkit/PermissionRequest.java
+++ b/core/java/android/webkit/PermissionRequest.java
@@ -28,6 +28,7 @@
 public interface PermissionRequest {
     /**
      * Resource belongs to geolocation service.
+     * @hide - see b/14668406
      */
     public final static long RESOURCE_GEOLOCATION = 1 << 0;
     /**
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 25bcd44..ac12357 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -50,28 +50,6 @@
     private static WebViewFactoryProvider sProviderInstance;
     private static final Object sProviderLock = new Object();
 
-    public static boolean isExperimentalWebViewAvailable() {
-        // TODO: Remove callers of this method then remove it.
-        return false;  // Hide the toggle in Developer Settings.
-    }
-
-    /** @hide */
-    public static void setUseExperimentalWebView(boolean enable) {
-        // TODO: Remove callers of this method then remove it.
-    }
-
-    /** @hide */
-    public static boolean useExperimentalWebView() {
-        // TODO: Remove callers of this method then remove it.
-        return true;
-    }
-
-    /** @hide */
-    public static boolean isUseExperimentalWebViewSet() {
-        // TODO: Remove callers of this method then remove it.
-        return false;  // User has not modifed Developer Settings
-    }
-
     static WebViewFactoryProvider getProvider() {
         synchronized (sProviderLock) {
             // For now the main purpose of this function (and the factory abstraction) is to keep
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index cde8080..99a7886 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -276,6 +276,13 @@
      * @see Intent#ACTION_SEND_MULTIPLE
      */
     public void setShareIntent(Intent shareIntent) {
+        if (shareIntent != null) {
+            final String action = shareIntent.getAction();
+            if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+                shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+                        Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+            }
+        }
         ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
             mShareHistoryFileName);
         dataModel.setIntent(shareIntent);
@@ -292,7 +299,12 @@
             final int itemId = item.getItemId();
             Intent launchIntent = dataModel.chooseActivity(itemId);
             if (launchIntent != null) {
-                launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+                final String action = launchIntent.getAction();
+                if (Intent.ACTION_SEND.equals(action) ||
+                        Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+                    launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+                            Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+                }
                 mContext.startActivity(launchIntent);
             }
             return true;
@@ -308,7 +320,7 @@
             return;
         }
         if (mOnChooseActivityListener == null) {
-            mOnChooseActivityListener = new ShareAcitivityChooserModelPolicy();
+            mOnChooseActivityListener = new ShareActivityChooserModelPolicy();
         }
         ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
         dataModel.setOnChooseActivityListener(mOnChooseActivityListener);
@@ -317,7 +329,7 @@
     /**
      * Policy that delegates to the {@link OnShareTargetSelectedListener}, if such.
      */
-    private class ShareAcitivityChooserModelPolicy implements OnChooseActivityListener {
+    private class ShareActivityChooserModelPolicy implements OnChooseActivityListener {
         @Override
         public boolean onChooseActivity(ActivityChooserModel host, Intent intent) {
             if (mOnShareTargetSelectedListener != null) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b91111d..8f073de 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -289,6 +289,8 @@
     private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance();
 
     private float mShadowRadius, mShadowDx, mShadowDy;
+    private int mShadowColor;
+
 
     private boolean mPreDrawRegistered;
 
@@ -2755,6 +2757,7 @@
         mShadowRadius = radius;
         mShadowDx = dx;
         mShadowDy = dy;
+        mShadowColor = color;
 
         // Will change text clip region
         if (mEditor != null) mEditor.invalidateTextDisplayList();
@@ -2804,7 +2807,7 @@
      * @attr ref android.R.styleable#TextView_shadowColor
      */
     public int getShadowColor() {
-        return mTextPaint.shadowColor;
+        return mShadowColor;
     }
 
     /**
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 4726da7..b568121 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -26,6 +26,7 @@
 import android.content.res.TypedArray;
 import android.database.Cursor;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.text.TextUtils;
@@ -38,6 +39,7 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.Window;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
@@ -240,6 +242,7 @@
         mWindow.requestFeature(Window.FEATURE_NO_TITLE);
         mWindow.setContentView(mAlertDialogLayout);
         setupView();
+        setupDecor();
     }
     
     public void setTitle(CharSequence title) {
@@ -415,7 +418,28 @@
     public boolean onKeyUp(int keyCode, KeyEvent event) {
         return mScrollView != null && mScrollView.executeKeyEvent(event);
     }
-    
+
+    private void setupDecor() {
+        final View decor = mWindow.getDecorView();
+        final View parent = mWindow.findViewById(R.id.parentPanel);
+        if (parent != null && decor != null) {
+            decor.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
+                @Override
+                public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
+                    if (insets.isRound()) {
+                        // TODO: Get the padding as a function of the window size.
+                        int roundOffset = mContext.getResources().getDimensionPixelOffset(
+                                R.dimen.alert_dialog_round_padding);
+                        parent.setPadding(roundOffset, roundOffset, roundOffset, roundOffset);
+                    }
+                    return insets.consumeSystemWindowInsets();
+                }
+            });
+            decor.setFitsSystemWindows(true);
+            decor.requestApplyInsets();
+        }
+    }
+
     private void setupView() {
         LinearLayout contentPanel = (LinearLayout) mWindow.findViewById(R.id.contentPanel);
         setupContent(contentPanel);
@@ -636,14 +660,31 @@
 
     private void setBackground(TypedArray a, View topPanel, View contentPanel, View customPanel,
             View buttonPanel, boolean hasTitle, boolean hasCustomView, boolean hasButtons) {
-        final int topBright = a.getResourceId(
-                R.styleable.AlertDialog_topBright, R.drawable.popup_top_bright);
-        final int topDark = a.getResourceId(
-                R.styleable.AlertDialog_topDark, R.drawable.popup_top_dark);
-        final int centerBright = a.getResourceId(
-                R.styleable.AlertDialog_centerBright, R.drawable.popup_center_bright);
-        final int centerDark = a.getResourceId(
-                R.styleable.AlertDialog_centerDark, R.drawable.popup_center_dark);
+        int fullDark = 0;
+        int topDark = 0;
+        int centerDark = 0;
+        int bottomDark = 0;
+        int fullBright = 0;
+        int topBright = 0;
+        int centerBright = 0;
+        int bottomBright = 0;
+        int bottomMedium = 0;
+        if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.KITKAT) {
+            fullDark = R.drawable.popup_full_dark;
+            topDark = R.drawable.popup_top_dark;
+            centerDark = R.drawable.popup_center_dark;
+            bottomDark = R.drawable.popup_bottom_dark;
+            fullBright = R.drawable.popup_full_bright;
+            topBright = R.drawable.popup_top_bright;
+            centerBright = R.drawable.popup_center_bright;
+            bottomBright = R.drawable.popup_bottom_bright;
+            bottomMedium = R.drawable.popup_bottom_medium;
+        }
+        topBright = a.getResourceId(R.styleable.AlertDialog_topBright, topBright);
+        topDark = a.getResourceId(R.styleable.AlertDialog_topDark, topDark);
+        centerBright = a.getResourceId(R.styleable.AlertDialog_centerBright, centerBright);
+        centerDark = a.getResourceId(R.styleable.AlertDialog_centerDark, centerDark);
+
 
         /* We now set the background of all of the sections of the alert.
          * First collect together each section that is being displayed along
@@ -707,22 +748,17 @@
 
         if (lastView != null) {
             if (setView) {
-                final int bottomBright = a.getResourceId(
-                        R.styleable.AlertDialog_bottomBright, R.drawable.popup_bottom_bright);
-                final int bottomMedium = a.getResourceId(
-                        R.styleable.AlertDialog_bottomMedium, R.drawable.popup_bottom_medium);
-                final int bottomDark = a.getResourceId(
-                        R.styleable.AlertDialog_bottomDark, R.drawable.popup_bottom_dark);
+                bottomBright = a.getResourceId(R.styleable.AlertDialog_bottomBright, bottomBright);
+                bottomMedium = a.getResourceId(R.styleable.AlertDialog_bottomMedium, bottomMedium);
+                bottomDark = a.getResourceId(R.styleable.AlertDialog_bottomDark, bottomDark);
 
                 // ListViews will use the Bright background, but buttons use the
                 // Medium background.
                 lastView.setBackgroundResource(
                         lastLight ? (hasButtons ? bottomMedium : bottomBright) : bottomDark);
             } else {
-                final int fullBright = a.getResourceId(
-                        R.styleable.AlertDialog_fullBright, R.drawable.popup_full_bright);
-                final int fullDark = a.getResourceId(
-                        R.styleable.AlertDialog_fullDark, R.drawable.popup_full_dark);
+                fullBright = a.getResourceId(R.styleable.AlertDialog_fullBright, fullBright);
+                fullDark = a.getResourceId(R.styleable.AlertDialog_fullDark, fullDark);
 
                 lastView.setBackgroundResource(lastLight ? fullBright : fullDark);
             }
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 1eda373..106ac0b 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -33,6 +33,14 @@
             return;
         }
         Intent target = (Intent)targetParcelable;
+        if (target != null) {
+            final String action = target.getAction();
+            if (Intent.ACTION_SEND.equals(action) ||
+                    Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+                target.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+                        Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+            }
+        }
         CharSequence title = intent.getCharSequenceExtra(Intent.EXTRA_TITLE);
         if (title == null) {
             title = getResources().getText(com.android.internal.R.string.chooseActivity);
@@ -43,13 +51,19 @@
             initialIntents = new Intent[pa.length];
             for (int i=0; i<pa.length; i++) {
                 if (!(pa[i] instanceof Intent)) {
-                    Log.w("ChooserActivity", "Initial intent #" + i
-                            + " not an Intent: " + pa[i]);
+                    Log.w("ChooserActivity", "Initial intent #" + i + " not an Intent: " + pa[i]);
                     finish();
                     super.onCreate(null);
                     return;
                 }
-                initialIntents[i] = (Intent)pa[i];
+                final Intent in = (Intent) pa[i];
+                final String action = in.getAction();
+                if (Intent.ACTION_SEND.equals(action) ||
+                        Intent.ACTION_SEND_MULTIPLE.equals(action)) {
+                    in.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
+                            Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+                }
+                initialIntents[i] = in;
             }
         }
         super.onCreate(savedInstanceState, target, title, initialIntents, null, false);
diff --git a/core/java/com/android/internal/app/IUsageStats.aidl b/core/java/com/android/internal/app/IUsageStats.aidl
index 1ea7409..7e7f0e1 100644
--- a/core/java/com/android/internal/app/IUsageStats.aidl
+++ b/core/java/com/android/internal/app/IUsageStats.aidl
@@ -16,13 +16,17 @@
 
 package com.android.internal.app;
 
+import android.app.UsageStats;
 import android.content.ComponentName;
-import com.android.internal.os.PkgUsageStats;
+import android.content.res.Configuration;
+import android.os.ParcelableParcel;
 
 interface IUsageStats {
     void noteResumeComponent(in ComponentName componentName);
     void notePauseComponent(in ComponentName componentName);
     void noteLaunchTime(in ComponentName componentName, int millis);
-    PkgUsageStats getPkgUsageStats(in ComponentName componentName);
-    PkgUsageStats[] getAllPkgUsageStats();
+    void noteStartConfig(in Configuration config);
+    UsageStats.PackageStats getPkgUsageStats(String callingPkg, in ComponentName componentName);
+    UsageStats.PackageStats[] getAllPkgUsageStats(String callingPkg);
+    ParcelableParcel getCurrentStats(String callingPkg);
 }
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 8cdaf91..abd1791 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -18,156 +18,122 @@
 
 import android.app.Activity;
 import android.content.ActivityNotFoundException;
+import android.content.ContentResolver;
+import android.content.Context;
 import android.content.Intent;
+import android.graphics.Color;
 import android.graphics.Typeface;
-import android.provider.Settings;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Handler;
-import android.text.method.AllCapsTransformationMethod;
+import android.provider.Settings;
+import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.view.Gravity;
 import android.view.View;
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AnticipateOvershootInterpolator;
-import android.view.animation.DecelerateInterpolator;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.TextView;
 
 public class PlatLogoActivity extends Activity {
-    FrameLayout mContent;
-    int mCount;
-    final Handler mHandler = new Handler();
-    static final int BGCOLOR = 0xffed1d24;
+    private static class Torso extends FrameLayout {
+        boolean mAnimate = false;
+        TextView mText;
+
+        public Torso(Context context) {
+            this(context, null);
+        }
+        public Torso(Context context, AttributeSet attrs) {
+            this(context, attrs, 0);
+        }
+        public Torso(Context context, AttributeSet attrs, int flags) {
+            super(context, attrs, flags);
+
+            for (int i=0; i<2; i++) {
+                final View v = new View(context);
+                v.setBackgroundColor(i % 2 == 0 ? Color.BLUE : Color.RED);
+                addView(v);
+            }
+
+            mText = new TextView(context);
+            mText.setTextColor(Color.BLACK);
+            mText.setTextSize(14 /* sp */);
+            mText.setTypeface(Typeface.create("monospace", Typeface.BOLD));
+
+            addView(mText, new FrameLayout.LayoutParams(
+                    FrameLayout.LayoutParams.MATCH_PARENT,
+                    FrameLayout.LayoutParams.WRAP_CONTENT,
+                    Gravity.BOTTOM | Gravity.LEFT
+            ));
+        }
+
+        private Runnable mRunnable = new Runnable() {
+            @Override
+            public void run() {
+                mText.setText(String.format("android_%s.flv - build %s",
+                        Build.VERSION.CODENAME,
+                        Build.VERSION.INCREMENTAL));
+                final int N = getChildCount();
+                final float parentw = getMeasuredWidth();
+                final float parenth = getMeasuredHeight();
+                for (int i=0; i<N; i++) {
+                    final View v = getChildAt(i);
+                    if (v instanceof TextView) continue;
+
+                    final int w = (int) (Math.random() * parentw);
+                    final int h = (int) (Math.random() * parenth);
+                    v.setLayoutParams(new FrameLayout.LayoutParams(w, h));
+
+                    v.setX((float) Math.random() * (parentw - w));
+                    v.setY((float) Math.random() * (parenth - h));
+                }
+
+                if (mAnimate) postDelayed(this, 1000);
+            }
+        };
+        @Override
+        protected void onAttachedToWindow() {
+            mAnimate = true;
+            post(mRunnable);
+        }
+        @Override
+        protected void onDetachedFromWindow() {
+            mAnimate = false;
+            removeCallbacks(mRunnable);
+        }
+    }
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        DisplayMetrics metrics = new DisplayMetrics();
-        getWindowManager().getDefaultDisplay().getMetrics(metrics);
+        final Torso t = new Torso(this);
+        t.setBackgroundColor(Color.WHITE);
 
-        Typeface bold = Typeface.create("sans-serif", Typeface.BOLD);
-        Typeface light = Typeface.create("sans-serif-light", Typeface.NORMAL);
+        t.getChildAt(0)
+                .setOnLongClickListener(new View.OnLongClickListener() {
+                    @Override
+                    public boolean onLongClick(View v) {
+                        final ContentResolver cr = getContentResolver();
+                        if (Settings.System.getLong(cr, Settings.System.EGG_MODE, 0)
+                                == 0) {
+                            // For posterity: the moment this user unlocked the easter egg
+                            Settings.System.putLong(cr,
+                                    Settings.System.EGG_MODE,
+                                    System.currentTimeMillis());
+                        }
+                        try {
+                            startActivity(new Intent(Intent.ACTION_MAIN)
+                                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                                            | Intent.FLAG_ACTIVITY_CLEAR_TASK
+                                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+                                    .addCategory("com.android.internal.category.PLATLOGO"));
+                        } catch (ActivityNotFoundException ex) {
+                            android.util.Log.e("PlatLogoActivity", "Couldn't catch a break.");
+                        }
+                        finish();
+                        return true;
+                    }
+                });
 
-        mContent = new FrameLayout(this);
-        mContent.setBackgroundColor(0xC0000000);
-        
-        final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
-                FrameLayout.LayoutParams.WRAP_CONTENT,
-                FrameLayout.LayoutParams.WRAP_CONTENT);
-        lp.gravity = Gravity.CENTER;
-
-        final ImageView logo = new ImageView(this);
-        logo.setImageResource(com.android.internal.R.drawable.platlogo);
-        logo.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
-        logo.setVisibility(View.INVISIBLE);
-
-        final View bg = new View(this);
-        bg.setBackgroundColor(BGCOLOR);
-        bg.setAlpha(0f);
-
-        final TextView letter = new TextView(this);
-
-        letter.setTypeface(bold);
-        letter.setTextSize(300);
-        letter.setTextColor(0xFFFFFFFF);
-        letter.setGravity(Gravity.CENTER);
-        letter.setText(String.valueOf(Build.ID).substring(0, 1));
-
-        final int p = (int)(4 * metrics.density);
-
-        final TextView tv = new TextView(this);
-        if (light != null) tv.setTypeface(light);
-        tv.setTextSize(30);
-        tv.setPadding(p, p, p, p);
-        tv.setTextColor(0xFFFFFFFF);
-        tv.setGravity(Gravity.CENTER);
-        tv.setTransformationMethod(new AllCapsTransformationMethod(this));
-        tv.setText("Android " + Build.VERSION.RELEASE);
-        tv.setVisibility(View.INVISIBLE);
-
-        mContent.addView(bg);
-        mContent.addView(letter, lp);
-        mContent.addView(logo, lp);
-
-        final FrameLayout.LayoutParams lp2 = new FrameLayout.LayoutParams(lp);
-        lp2.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
-        lp2.bottomMargin = 10*p;
-
-        mContent.addView(tv, lp2);
-
-        mContent.setOnClickListener(new View.OnClickListener() {
-            int clicks;
-            @Override
-            public void onClick(View v) {
-                clicks++;
-                if (clicks >= 6) {
-                    mContent.performLongClick();
-                    return;
-                }
-                letter.animate().cancel();
-                final float offset = (int)letter.getRotation() % 360;
-                letter.animate()
-                    .rotationBy((Math.random() > 0.5f ? 360 : -360) - offset)
-                    .setInterpolator(new DecelerateInterpolator())
-                    .setDuration(700).start();
-            }
-        });
-
-        mContent.setOnLongClickListener(new View.OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                if (logo.getVisibility() != View.VISIBLE) {
-                    bg.setScaleX(0.01f);
-                    bg.animate().alpha(1f).scaleX(1f).setStartDelay(500).start();
-                    letter.animate().alpha(0f).scaleY(0.5f).scaleX(0.5f)
-                            .rotationBy(360)
-                            .setInterpolator(new AccelerateInterpolator())
-                            .setDuration(1000)
-                            .start();
-                    logo.setAlpha(0f);
-                    logo.setVisibility(View.VISIBLE);
-                    logo.setScaleX(0.5f);
-                    logo.setScaleY(0.5f);
-                    logo.animate().alpha(1f).scaleX(1f).scaleY(1f)
-                        .setDuration(1000).setStartDelay(500)
-                        .setInterpolator(new AnticipateOvershootInterpolator())
-                        .start();
-                    tv.setAlpha(0f);
-                    tv.setVisibility(View.VISIBLE);
-                    tv.animate().alpha(1f).setDuration(1000).setStartDelay(1000).start();
-                    return true;
-                }
-                return false;
-            }
-        });
-
-        logo.setOnLongClickListener(new View.OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                if (Settings.System.getLong(getContentResolver(), Settings.System.EGG_MODE, 0)
-                        == 0) {
-                    // For posterity: the moment this user unlocked the easter egg
-                    Settings.System.putLong(getContentResolver(),
-                            Settings.System.EGG_MODE,
-                            System.currentTimeMillis());
-                }
-                try {
-                    startActivity(new Intent(Intent.ACTION_MAIN)
-                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                            | Intent.FLAG_ACTIVITY_CLEAR_TASK
-                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
-                        .addCategory("com.android.internal.category.PLATLOGO"));
-                } catch (ActivityNotFoundException ex) {
-                    android.util.Log.e("PlatLogoActivity", "Couldn't catch a break.");
-                }
-                finish();
-                return true;
-            }
-        });
-        
-        setContentView(mContent);
+        setContentView(t);
     }
 }
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 882bec9..41f3337 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -1108,13 +1108,6 @@
                 mRuntime = runtime;
             }
         }
-        String webview = WebViewFactory.useExperimentalWebView() ? "chromeview" : "webview";
-        if (!Objects.equals(webview, mWebView)) {
-            changed = true;
-            if (update) {
-                mWebView = webview;
-            }
-        }
         return changed;
     }
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 1aff190..7bd5b12 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -188,8 +188,7 @@
 
     boolean mShuttingDown;
 
-    HashMap<String, SparseBooleanArray>[] mActiveEvents
-            = (HashMap<String, SparseBooleanArray>[]) new HashMap[HistoryItem.EVENT_COUNT];
+    final HistoryEventTracker mActiveEvents = new HistoryEventTracker();
 
     long mHistoryBaseTime;
     boolean mHaveBatteryLevel = false;
@@ -2297,44 +2296,8 @@
 
     public void noteEventLocked(int code, String name, int uid) {
         uid = mapUid(uid);
-        if ((code&HistoryItem.EVENT_FLAG_START) != 0) {
-            int idx = code&~HistoryItem.EVENT_FLAG_START;
-            HashMap<String, SparseBooleanArray> active = mActiveEvents[idx];
-            if (active == null) {
-                active = new HashMap<String, SparseBooleanArray>();
-                mActiveEvents[idx] = active;
-            }
-            SparseBooleanArray uids = active.get(name);
-            if (uids == null) {
-                uids = new SparseBooleanArray();
-                active.put(name, uids);
-            }
-            if (uids.get(uid)) {
-                // Already set, nothing to do!
-                return;
-            }
-            uids.put(uid, true);
-        } else if ((code&HistoryItem.EVENT_FLAG_FINISH) != 0) {
-            int idx = code&~HistoryItem.EVENT_FLAG_FINISH;
-            HashMap<String, SparseBooleanArray> active = mActiveEvents[idx];
-            if (active == null) {
-                // not currently active, nothing to do.
-                return;
-            }
-            SparseBooleanArray uids = active.get(name);
-            if (uids == null) {
-                // not currently active, nothing to do.
-                return;
-            }
-            idx = uids.indexOfKey(uid);
-            if (idx < 0 || !uids.valueAt(idx)) {
-                // not currently active, nothing to do.
-                return;
-            }
-            uids.removeAt(idx);
-            if (uids.size() <= 0) {
-                active.remove(name);
-            }
+        if (!mActiveEvents.updateState(code, name, uid, 0)) {
+            return;
         }
         final long elapsedRealtime = SystemClock.elapsedRealtime();
         final long uptime = SystemClock.uptimeMillis();
@@ -2348,6 +2311,9 @@
         }
     }
 
+    private String mInitialAcquireWakeName;
+    private int mInitialAcquireWakeUid = -1;
+
     public void noteStartWakeLocked(int uid, int pid, String name, String historyName, int type,
             boolean unimportantForLogging, long elapsedRealtime, long uptime) {
         uid = mapUid(uid);
@@ -2360,8 +2326,9 @@
                 if (DEBUG_HISTORY) Slog.v(TAG, "Start wake lock to: "
                         + Integer.toHexString(mHistoryCur.states));
                 mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
-                mHistoryCur.wakelockTag.string = historyName != null ? historyName : name;
-                mHistoryCur.wakelockTag.uid = uid;
+                mHistoryCur.wakelockTag.string = mInitialAcquireWakeName
+                        = historyName != null ? historyName : name;
+                mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
                 mWakeLockImportant = !unimportantForLogging;
                 addHistoryRecordLocked(elapsedRealtime, uptime);
             } else if (!mWakeLockImportant && !unimportantForLogging) {
@@ -2369,8 +2336,9 @@
                     // We'll try to update the last tag.
                     mHistoryLastWritten.wakelockTag = null;
                     mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
-                    mHistoryCur.wakelockTag.string = historyName != null ? historyName : name;
-                    mHistoryCur.wakelockTag.uid = uid;
+                    mHistoryCur.wakelockTag.string = mInitialAcquireWakeName
+                            = historyName != null ? historyName : name;
+                    mHistoryCur.wakelockTag.uid = mInitialAcquireWakeUid = uid;
                     addHistoryRecordLocked(elapsedRealtime, uptime);
                 }
                 mWakeLockImportant = true;
@@ -2395,6 +2363,14 @@
                 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))
+                        || uid != mInitialAcquireWakeUid) {
+                    mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+                    mHistoryCur.wakelockTag.string = name;
+                    mHistoryCur.wakelockTag.uid = uid;
+                }
+                mInitialAcquireWakeName = null;
+                mInitialAcquireWakeUid = -1;
                 addHistoryRecordLocked(elapsedRealtime, uptime);
             }
         }
@@ -5699,7 +5675,8 @@
         final long lastRealtime = out.time;
         final long lastWalltime = out.currentTime;
         readHistoryDelta(mHistoryBuffer, out);
-        if (out.cmd != HistoryItem.CMD_CURRENT_TIME && lastWalltime != 0) {
+        if (out.cmd != HistoryItem.CMD_CURRENT_TIME
+                && out.cmd != HistoryItem.CMD_RESET && lastWalltime != 0) {
             out.currentTime = lastWalltime + (out.time - lastRealtime);
         }
         return true;
@@ -5845,17 +5822,15 @@
 
     private void initActiveHistoryEventsLocked(long elapsedRealtimeMs, long uptimeMs) {
         for (int i=0; i<HistoryItem.EVENT_COUNT; i++) {
-            HashMap<String, SparseBooleanArray> active = mActiveEvents[i];
+            HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(i);
             if (active == null) {
                 continue;
             }
-            for (HashMap.Entry<String, SparseBooleanArray> ent : active.entrySet()) {
-                SparseBooleanArray uids = ent.getValue();
+            for (HashMap.Entry<String, SparseIntArray> ent : active.entrySet()) {
+                SparseIntArray uids = ent.getValue();
                 for (int j=0; j<uids.size(); j++) {
-                    if (uids.valueAt(j)) {
-                        addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, i, ent.getKey(),
-                                uids.keyAt(j));
-                    }
+                    addHistoryEventLocked(elapsedRealtimeMs, uptimeMs, i, ent.getKey(),
+                            uids.keyAt(j));
                 }
             }
         }
@@ -5971,7 +5946,8 @@
             boolean reset) {
         mRecordingHistory = true;
         mHistoryCur.currentTime = System.currentTimeMillis();
-        addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_CURRENT_TIME,
+        addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs,
+                reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME,
                 mHistoryCur);
         mHistoryCur.currentTime = 0;
         if (reset) {
diff --git a/core/java/com/android/internal/os/PkgUsageStats.aidl b/core/java/com/android/internal/os/PkgUsageStats.aidl
deleted file mode 100644
index 8305271..0000000
--- a/core/java/com/android/internal/os/PkgUsageStats.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/* //device/java/android/android/content/Intent.aidl
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
-
-package com.android.internal.os;
-
-parcelable PkgUsageStats;
diff --git a/core/java/com/android/internal/os/PkgUsageStats.java b/core/java/com/android/internal/os/PkgUsageStats.java
deleted file mode 100644
index 8c2c405..0000000
--- a/core/java/com/android/internal/os/PkgUsageStats.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.os;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * implementation of PkgUsageStats associated with an
- * application package.
- *  @hide
- */
-public class PkgUsageStats implements Parcelable {
-    public String packageName;
-    public int launchCount;
-    public long usageTime;
-    public Map<String, Long> componentResumeTimes;
-    
-    public static final Parcelable.Creator<PkgUsageStats> CREATOR
-    = new Parcelable.Creator<PkgUsageStats>() {
-        public PkgUsageStats createFromParcel(Parcel in) {
-            return new PkgUsageStats(in);
-        }
-
-        public PkgUsageStats[] newArray(int size) {
-            return new PkgUsageStats[size];
-        }
-    };
-    
-    public String toString() {
-        return "PkgUsageStats{"
-        + Integer.toHexString(System.identityHashCode(this))
-        + " " + packageName + "}";
-    }
-    
-    public PkgUsageStats(String pkgName, int count, long time, Map<String, Long> lastResumeTimes) {
-        packageName = pkgName;
-        launchCount = count;
-        usageTime = time;
-        componentResumeTimes = new HashMap<String, Long>(lastResumeTimes);
-    }
-    
-    public PkgUsageStats(Parcel source) {
-        packageName = source.readString();
-        launchCount = source.readInt();
-        usageTime = source.readLong();
-        final int N = source.readInt();
-        componentResumeTimes = new HashMap<String, Long>(N);
-        for (int i = 0; i < N; i++) {
-            String component = source.readString();
-            long lastResumeTime = source.readLong();
-            componentResumeTimes.put(component, lastResumeTime);
-        }
-    }
-    
-    public PkgUsageStats(PkgUsageStats pStats) {
-        packageName = pStats.packageName;
-        launchCount = pStats.launchCount;
-        usageTime = pStats.usageTime;
-        componentResumeTimes = new HashMap<String, Long>(pStats.componentResumeTimes);
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public void writeToParcel(Parcel dest, int parcelableFlags) {
-        dest.writeString(packageName);
-        dest.writeInt(launchCount);
-        dest.writeLong(usageTime);
-        dest.writeInt(componentResumeTimes.size());
-        for (Map.Entry<String, Long> ent : componentResumeTimes.entrySet()) {
-            dest.writeString(ent.getKey());
-            dest.writeLong(ent.getValue());
-        }
-    }
-}
diff --git a/core/java/com/android/internal/util/LegacyNotificationUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
similarity index 93%
rename from core/java/com/android/internal/util/LegacyNotificationUtil.java
rename to core/java/com/android/internal/util/NotificationColorUtil.java
index 0394bbc..f38cbde 100644
--- a/core/java/com/android/internal/util/LegacyNotificationUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -24,6 +24,7 @@
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.VectorDrawable;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
 import android.text.style.TextAppearanceSpan;
@@ -38,21 +39,21 @@
  *
  * @hide
  */
-public class LegacyNotificationUtil {
+public class NotificationColorUtil {
 
-    private static final String TAG = "LegacyNotificationUtil";
+    private static final String TAG = "NotificationColorUtil";
 
     private static final Object sLock = new Object();
-    private static LegacyNotificationUtil sInstance;
+    private static NotificationColorUtil sInstance;
 
     private final ImageUtils mImageUtils = new ImageUtils();
     private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache =
             new WeakHashMap<Bitmap, Pair<Boolean, Integer>>();
 
-    public static LegacyNotificationUtil getInstance() {
+    public static NotificationColorUtil getInstance() {
         synchronized (sLock) {
             if (sInstance == null) {
-                sInstance = new LegacyNotificationUtil();
+                sInstance = new NotificationColorUtil();
             }
             return sInstance;
         }
@@ -107,6 +108,9 @@
             AnimationDrawable ad = (AnimationDrawable) d;
             int count = ad.getNumberOfFrames();
             return count > 0 && isGrayscale(ad.getFrame(0));
+        } else if (d instanceof VectorDrawable) {
+            // We just assume you're doing the right thing if using vectors
+            return true;
         } else {
             return false;
         }
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index b380403..bc92c4a 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -46,6 +46,8 @@
     public static final int BASE_WIFI_MONITOR                                       = 0x00024000;
     public static final int BASE_WIFI_MANAGER                                       = 0x00025000;
     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_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/util/VirtualRefBasePtr.java b/core/java/com/android/internal/util/VirtualRefBasePtr.java
new file mode 100644
index 0000000..0bd4d3a
--- /dev/null
+++ b/core/java/com/android/internal/util/VirtualRefBasePtr.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.internal.util;
+
+/**
+ * Helper class that contains a strong reference to a VirtualRefBase native
+ * object. This will incStrong in the ctor, and decStrong in the finalizer
+ */
+public final class VirtualRefBasePtr {
+    private long mNativePtr;
+
+    public VirtualRefBasePtr(long ptr) {
+        mNativePtr = ptr;
+        nIncStrong(mNativePtr);
+    }
+
+    public long get() {
+        return mNativePtr;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            nDecStrong(mNativePtr);
+            mNativePtr = 0;
+        } finally {
+            super.finalize();
+        }
+    }
+
+    private static native void nIncStrong(long ptr);
+    private static native void nDecStrong(long ptr);
+}
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
index 90210ce..367b713 100644
--- a/core/java/com/android/internal/view/IInputMethodSession.aidl
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -21,6 +21,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.ExtractedText;
 
 /**
@@ -47,4 +48,6 @@
     void toggleSoftInput(int showFlags, int hideFlags);
 
     void finishSession();
+
+    void updateCursorAnchorInfo(in CursorAnchorInfo cursorAnchorInfo);
 }
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index 674d084..bcfa036 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -35,7 +35,7 @@
 public class SwipeDismissLayout extends FrameLayout {
     private static final String TAG = "SwipeDismissLayout";
 
-    private static final float DISMISS_MIN_PROGRESS = 0.6f;
+    private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .4f;
 
     public interface OnDismissedListener {
         void onDismissed(SwipeDismissLayout layout);
@@ -244,7 +244,11 @@
         if (!mSwiping) {
             float deltaX = ev.getRawX() - mDownX;
             float deltaY = ev.getRawY() - mDownY;
-            mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2;
+            if ((deltaX * deltaX) + (deltaY * deltaY) > mSlop * mSlop) {
+                mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2;
+            } else {
+                mSwiping = false;
+            }
         }
     }
 
@@ -254,12 +258,7 @@
             mVelocityTracker.addMovement(ev);
             mVelocityTracker.computeCurrentVelocity(1000);
 
-            float velocityX = mVelocityTracker.getXVelocity();
-            float absVelocityX = Math.abs(velocityX);
-            float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
-
-            if (deltaX > (getWidth() * DISMISS_MIN_PROGRESS) &&
-                    absVelocityX < mMinFlingVelocity && 
+            if (deltaX > (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO) &&
                     ev.getRawX() >= mLastX) {
                 mDismissed = true;
             }
@@ -267,7 +266,7 @@
         // Check if the user tried to undo this.
         if (mDismissed && mSwiping) {
             // Check if the user's finger is actually back
-            if (deltaX < (getWidth() * DISMISS_MIN_PROGRESS)) {
+            if (deltaX < (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO)) {
                 mDismissed = false;
             }
         }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 8bd2e4f..26f77b5 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -155,7 +155,8 @@
 	android_content_res_Configuration.cpp \
 	android_animation_PropertyValuesHolder.cpp \
 	com_android_internal_net_NetworkStatsFactory.cpp \
-	com_android_internal_os_Zygote.cpp
+	com_android_internal_os_Zygote.cpp \
+	com_android_internal_util_VirtualRefBasePtr.cpp
 
 LOCAL_C_INCLUDES += \
 	$(JNI_H_INCLUDE) \
@@ -241,8 +242,6 @@
 # <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
 LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
 
-LOCAL_LDLIBS += -lpthread -ldl
-
 ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
 	LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
 endif
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 66fbb8e..9941cd9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -181,6 +181,7 @@
 extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
 extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
 extern int register_com_android_internal_os_Zygote(JNIEnv *env);
+extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
 
 static AndroidRuntime* gCurRuntime = NULL;
 
@@ -1262,6 +1263,7 @@
     REG_JNI(register_android_os_MemoryFile),
     REG_JNI(register_com_android_internal_os_ZygoteInit),
     REG_JNI(register_com_android_internal_os_Zygote),
+    REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
     REG_JNI(register_android_hardware_Camera),
     REG_JNI(register_android_hardware_camera2_CameraMetadata),
     REG_JNI(register_android_hardware_SensorManager),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index e0fa9ba4..0328517 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1,838 +1,838 @@
-#include "SkBitmap.h"

-#include "SkPixelRef.h"

-#include "SkImageEncoder.h"

-#include "SkColorPriv.h"

-#include "GraphicsJNI.h"

-#include "SkDither.h"

-#include "SkUnPreMultiply.h"

-#include "SkStream.h"

-

-#include <binder/Parcel.h>

-#include "android_os_Parcel.h"

-#include "android_util_Binder.h"

-#include "android_nio_utils.h"

-#include "CreateJavaOutputStreamAdaptor.h"

-

-#include <jni.h>

-

-#include <Caches.h>

-

-#if 0

-    #define TRACE_BITMAP(code)  code

-#else

-    #define TRACE_BITMAP(code)

-#endif

-

-///////////////////////////////////////////////////////////////////////////////

-// Conversions to/from SkColor, for get/setPixels, and the create method, which

-// is basically like setPixels

-

-typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,

-                              int x, int y);

-

-static void FromColor_D32(void* dst, const SkColor src[], int width,

-                          int, int) {

-    SkPMColor* d = (SkPMColor*)dst;

-

-    for (int i = 0; i < width; i++) {

-        *d++ = SkPreMultiplyColor(*src++);

-    }

-}

-

-static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,

-                          int, int) {

-    // SkColor's ordering may be different from SkPMColor

-    if (SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER) {

-        memcpy(dst, src, width * sizeof(SkColor));

-        return;

-    }

-

-    // order isn't same, repack each pixel manually

-    SkPMColor* d = (SkPMColor*)dst;

-    for (int i = 0; i < width; i++) {

-        SkColor c = *src++;

-        *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),

-                                   SkColorGetG(c), SkColorGetB(c));

-    }

-}

-

-static void FromColor_D565(void* dst, const SkColor src[], int width,

-                           int x, int y) {

-    uint16_t* d = (uint16_t*)dst;

-

-    DITHER_565_SCAN(y);

-    for (int stop = x + width; x < stop; x++) {

-        SkColor c = *src++;

-        *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),

-                                DITHER_VALUE(x));

-    }

-}

-

-static void FromColor_D4444(void* dst, const SkColor src[], int width,

-                            int x, int y) {

-    SkPMColor16* d = (SkPMColor16*)dst;

-

-    DITHER_4444_SCAN(y);

-    for (int stop = x + width; x < stop; x++) {

-        SkPMColor pmc = SkPreMultiplyColor(*src++);

-        *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));

-//        *d++ = SkPixel32ToPixel4444(pmc);

-    }

-}

-

-static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,

-                            int x, int y) {

-    SkPMColor16* d = (SkPMColor16*)dst;

-

-    DITHER_4444_SCAN(y);

-    for (int stop = x + width; x < stop; x++) {

-        SkColor c = *src++;

-

-        // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied

-        SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),

-                                            SkColorGetG(c), SkColorGetB(c));

-        *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));

-//        *d++ = SkPixel32ToPixel4444(pmc);

-    }

-}

-

-// can return NULL

-static FromColorProc ChooseFromColorProc(SkBitmap::Config config, bool isPremultiplied) {

-    switch (config) {

-        case SkBitmap::kARGB_8888_Config:

-            return isPremultiplied ? FromColor_D32 : FromColor_D32_Raw;

-        case SkBitmap::kARGB_4444_Config:

-            return isPremultiplied ? FromColor_D4444 : FromColor_D4444_Raw;

-        case SkBitmap::kRGB_565_Config:

-            return FromColor_D565;

-        default:

-            break;

-    }

-    return NULL;

-}

-

-bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,

-        int x, int y, int width, int height,

-        const SkBitmap& dstBitmap, bool isPremultiplied) {

-    SkAutoLockPixels alp(dstBitmap);

-    void* dst = dstBitmap.getPixels();

-    FromColorProc proc = ChooseFromColorProc(dstBitmap.config(), isPremultiplied);

-

-    if (NULL == dst || NULL == proc) {

-        return false;

-    }

-

-    const jint* array = env->GetIntArrayElements(srcColors, NULL);

-    const SkColor* src = (const SkColor*)array + srcOffset;

-

-    // reset to to actual choice from caller

-    dst = dstBitmap.getAddr(x, y);

-    // now copy/convert each scanline

-    for (int y = 0; y < height; y++) {

-        proc(dst, src, width, x, y);

-        src += srcStride;

-        dst = (char*)dst + dstBitmap.rowBytes();

-    }

-

-    dstBitmap.notifyPixelsChanged();

-

-    env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),

-                                 JNI_ABORT);

-    return true;

-}

-

-//////////////////// ToColor procs

-

-typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,

-                            SkColorTable*);

-

-static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,

-                              SkColorTable*) {

-    SkASSERT(width > 0);

-    const SkPMColor* s = (const SkPMColor*)src;

-    do {

-        *dst++ = SkUnPreMultiply::PMColorToColor(*s++);

-    } while (--width != 0);

-}

-

-static void ToColor_S32_Raw(SkColor dst[], const void* src, int width,

-                              SkColorTable*) {

-    SkASSERT(width > 0);

-    const SkPMColor* s = (const SkPMColor*)src;

-    do {

-        SkPMColor c = *s++;

-        *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),

-                                SkGetPackedG32(c), SkGetPackedB32(c));

-    } while (--width != 0);

-}

-

-static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,

-                               SkColorTable*) {

-    SkASSERT(width > 0);

-    const SkPMColor* s = (const SkPMColor*)src;

-    do {

-        SkPMColor c = *s++;

-        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),

-                               SkGetPackedB32(c));

-    } while (--width != 0);

-}

-

-static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,

-                                SkColorTable*) {

-    SkASSERT(width > 0);

-    const SkPMColor16* s = (const SkPMColor16*)src;

-    do {

-        *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));

-    } while (--width != 0);

-}

-

-static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width,

-                                SkColorTable*) {

-    SkASSERT(width > 0);

-    const SkPMColor16* s = (const SkPMColor16*)src;

-    do {

-        SkPMColor c = SkPixel4444ToPixel32(*s++);

-        *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),

-                                SkGetPackedG32(c), SkGetPackedB32(c));

-    } while (--width != 0);

-}

-

-static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,

-                                 SkColorTable*) {

-    SkASSERT(width > 0);

-    const SkPMColor16* s = (const SkPMColor16*)src;

-    do {

-        SkPMColor c = SkPixel4444ToPixel32(*s++);

-        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),

-                               SkGetPackedB32(c));

-    } while (--width != 0);

-}

-

-static void ToColor_S565(SkColor dst[], const void* src, int width,

-                         SkColorTable*) {

-    SkASSERT(width > 0);

-    const uint16_t* s = (const uint16_t*)src;

-    do {

-        uint16_t c = *s++;

-        *dst++ =  SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),

-                                SkPacked16ToB32(c));

-    } while (--width != 0);

-}

-

-static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,

-                              SkColorTable* ctable) {

-    SkASSERT(width > 0);

-    const uint8_t* s = (const uint8_t*)src;

-    const SkPMColor* colors = ctable->lockColors();

-    do {

-        *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);

-    } while (--width != 0);

-    ctable->unlockColors();

-}

-

-static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,

-                              SkColorTable* ctable) {

-    SkASSERT(width > 0);

-    const uint8_t* s = (const uint8_t*)src;

-    const SkPMColor* colors = ctable->lockColors();

-    do {

-        SkPMColor c = colors[*s++];

-        *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),

-                                SkGetPackedG32(c), SkGetPackedB32(c));

-    } while (--width != 0);

-    ctable->unlockColors();

-}

-

-static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,

-                               SkColorTable* ctable) {

-    SkASSERT(width > 0);

-    const uint8_t* s = (const uint8_t*)src;

-    const SkPMColor* colors = ctable->lockColors();

-    do {

-        SkPMColor c = colors[*s++];

-        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),

-                               SkGetPackedB32(c));

-    } while (--width != 0);

-    ctable->unlockColors();

-}

-

-// can return NULL

-static ToColorProc ChooseToColorProc(const SkBitmap& src, bool isPremultiplied) {

-    switch (src.config()) {

-        case SkBitmap::kARGB_8888_Config:

-            if (src.isOpaque()) return ToColor_S32_Opaque;

-            return isPremultiplied ? ToColor_S32_Alpha : ToColor_S32_Raw;

-        case SkBitmap::kARGB_4444_Config:

-            if (src.isOpaque()) return ToColor_S4444_Opaque;

-            return isPremultiplied ? ToColor_S4444_Alpha : ToColor_S4444_Raw;

-        case SkBitmap::kRGB_565_Config:

-            return ToColor_S565;

-        case SkBitmap::kIndex8_Config:

-            if (src.getColorTable() == NULL) {

-                return NULL;

-            }

-            if (src.isOpaque()) return ToColor_SI8_Opaque;

-            return isPremultiplied ? ToColor_SI8_Raw : ToColor_SI8_Alpha;

-        default:

-            break;

-    }

-    return NULL;

-}

-

-///////////////////////////////////////////////////////////////////////////////

-///////////////////////////////////////////////////////////////////////////////

-

-static int getPremulBitmapCreateFlags(bool isMutable) {

-    int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied;

-    if (isMutable) flags |= GraphicsJNI::kBitmapCreateFlag_Mutable;

-    return flags;

-}

-

-static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,

-                              jint offset, jint stride, jint width, jint height,

-                              jint configHandle, jboolean isMutable) {

-    SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);

-    if (NULL != jColors) {

-        size_t n = env->GetArrayLength(jColors);

-        if (n < SkAbs32(stride) * (size_t)height) {

-            doThrowAIOOBE(env);

-            return NULL;

-        }

-    }

-

-    // ARGB_4444 is a deprecated format, convert automatically to 8888

-    if (config == SkBitmap::kARGB_4444_Config) {

-        config = SkBitmap::kARGB_8888_Config;

-    }

-

-    SkBitmap bitmap;

-    bitmap.setConfig(config, width, height);

-

-    jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);

-    if (NULL == buff) {

-        return NULL;

-    }

-

-    if (jColors != NULL) {

-        GraphicsJNI::SetPixels(env, jColors, offset, stride,

-                0, 0, width, height, bitmap, true);

-    }

-

-    return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff,

-            getPremulBitmapCreateFlags(isMutable), NULL, NULL);

-}

-

-static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,

-                           jint dstConfigHandle, jboolean isMutable) {

-    const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);

-    SkBitmap::Config dstConfig = static_cast<SkBitmap::Config>(dstConfigHandle);

-    SkBitmap            result;

-    JavaPixelAllocator  allocator(env);

-

+#include "SkBitmap.h"
+#include "SkPixelRef.h"
+#include "SkImageEncoder.h"
+#include "SkColorPriv.h"
+#include "GraphicsJNI.h"
+#include "SkDither.h"
+#include "SkUnPreMultiply.h"
+#include "SkStream.h"
+
+#include <binder/Parcel.h>
+#include "android_os_Parcel.h"
+#include "android_util_Binder.h"
+#include "android_nio_utils.h"
+#include "CreateJavaOutputStreamAdaptor.h"
+
+#include <jni.h>
+
+#include <Caches.h>
+
+#if 0
+    #define TRACE_BITMAP(code)  code
+#else
+    #define TRACE_BITMAP(code)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Conversions to/from SkColor, for get/setPixels, and the create method, which
+// is basically like setPixels
+
+typedef void (*FromColorProc)(void* dst, const SkColor src[], int width,
+                              int x, int y);
+
+static void FromColor_D32(void* dst, const SkColor src[], int width,
+                          int, int) {
+    SkPMColor* d = (SkPMColor*)dst;
+
+    for (int i = 0; i < width; i++) {
+        *d++ = SkPreMultiplyColor(*src++);
+    }
+}
+
+static void FromColor_D32_Raw(void* dst, const SkColor src[], int width,
+                          int, int) {
+    // SkColor's ordering may be different from SkPMColor
+    if (SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER) {
+        memcpy(dst, src, width * sizeof(SkColor));
+        return;
+    }
+
+    // order isn't same, repack each pixel manually
+    SkPMColor* d = (SkPMColor*)dst;
+    for (int i = 0; i < width; i++) {
+        SkColor c = *src++;
+        *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
+                                   SkColorGetG(c), SkColorGetB(c));
+    }
+}
+
+static void FromColor_D565(void* dst, const SkColor src[], int width,
+                           int x, int y) {
+    uint16_t* d = (uint16_t*)dst;
+
+    DITHER_565_SCAN(y);
+    for (int stop = x + width; x < stop; x++) {
+        SkColor c = *src++;
+        *d++ = SkDitherRGBTo565(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
+                                DITHER_VALUE(x));
+    }
+}
+
+static void FromColor_D4444(void* dst, const SkColor src[], int width,
+                            int x, int y) {
+    SkPMColor16* d = (SkPMColor16*)dst;
+
+    DITHER_4444_SCAN(y);
+    for (int stop = x + width; x < stop; x++) {
+        SkPMColor pmc = SkPreMultiplyColor(*src++);
+        *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
+//        *d++ = SkPixel32ToPixel4444(pmc);
+    }
+}
+
+static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width,
+                            int x, int y) {
+    SkPMColor16* d = (SkPMColor16*)dst;
+
+    DITHER_4444_SCAN(y);
+    for (int stop = x + width; x < stop; x++) {
+        SkColor c = *src++;
+
+        // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied
+        SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c),
+                                            SkColorGetG(c), SkColorGetB(c));
+        *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x));
+//        *d++ = SkPixel32ToPixel4444(pmc);
+    }
+}
+
+// can return NULL
+static FromColorProc ChooseFromColorProc(SkBitmap::Config config, bool isPremultiplied) {
+    switch (config) {
+        case SkBitmap::kARGB_8888_Config:
+            return isPremultiplied ? FromColor_D32 : FromColor_D32_Raw;
+        case SkBitmap::kARGB_4444_Config:
+            return isPremultiplied ? FromColor_D4444 : FromColor_D4444_Raw;
+        case SkBitmap::kRGB_565_Config:
+            return FromColor_D565;
+        default:
+            break;
+    }
+    return NULL;
+}
+
+bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride,
+        int x, int y, int width, int height,
+        const SkBitmap& dstBitmap, bool isPremultiplied) {
+    SkAutoLockPixels alp(dstBitmap);
+    void* dst = dstBitmap.getPixels();
+    FromColorProc proc = ChooseFromColorProc(dstBitmap.config(), isPremultiplied);
+
+    if (NULL == dst || NULL == proc) {
+        return false;
+    }
+
+    const jint* array = env->GetIntArrayElements(srcColors, NULL);
+    const SkColor* src = (const SkColor*)array + srcOffset;
+
+    // reset to to actual choice from caller
+    dst = dstBitmap.getAddr(x, y);
+    // now copy/convert each scanline
+    for (int y = 0; y < height; y++) {
+        proc(dst, src, width, x, y);
+        src += srcStride;
+        dst = (char*)dst + dstBitmap.rowBytes();
+    }
+
+    dstBitmap.notifyPixelsChanged();
+
+    env->ReleaseIntArrayElements(srcColors, const_cast<jint*>(array),
+                                 JNI_ABORT);
+    return true;
+}
+
+//////////////////// ToColor procs
+
+typedef void (*ToColorProc)(SkColor dst[], const void* src, int width,
+                            SkColorTable*);
+
+static void ToColor_S32_Alpha(SkColor dst[], const void* src, int width,
+                              SkColorTable*) {
+    SkASSERT(width > 0);
+    const SkPMColor* s = (const SkPMColor*)src;
+    do {
+        *dst++ = SkUnPreMultiply::PMColorToColor(*s++);
+    } while (--width != 0);
+}
+
+static void ToColor_S32_Raw(SkColor dst[], const void* src, int width,
+                              SkColorTable*) {
+    SkASSERT(width > 0);
+    const SkPMColor* s = (const SkPMColor*)src;
+    do {
+        SkPMColor c = *s++;
+        *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
+                                SkGetPackedG32(c), SkGetPackedB32(c));
+    } while (--width != 0);
+}
+
+static void ToColor_S32_Opaque(SkColor dst[], const void* src, int width,
+                               SkColorTable*) {
+    SkASSERT(width > 0);
+    const SkPMColor* s = (const SkPMColor*)src;
+    do {
+        SkPMColor c = *s++;
+        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
+                               SkGetPackedB32(c));
+    } while (--width != 0);
+}
+
+static void ToColor_S4444_Alpha(SkColor dst[], const void* src, int width,
+                                SkColorTable*) {
+    SkASSERT(width > 0);
+    const SkPMColor16* s = (const SkPMColor16*)src;
+    do {
+        *dst++ = SkUnPreMultiply::PMColorToColor(SkPixel4444ToPixel32(*s++));
+    } while (--width != 0);
+}
+
+static void ToColor_S4444_Raw(SkColor dst[], const void* src, int width,
+                                SkColorTable*) {
+    SkASSERT(width > 0);
+    const SkPMColor16* s = (const SkPMColor16*)src;
+    do {
+        SkPMColor c = SkPixel4444ToPixel32(*s++);
+        *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
+                                SkGetPackedG32(c), SkGetPackedB32(c));
+    } while (--width != 0);
+}
+
+static void ToColor_S4444_Opaque(SkColor dst[], const void* src, int width,
+                                 SkColorTable*) {
+    SkASSERT(width > 0);
+    const SkPMColor16* s = (const SkPMColor16*)src;
+    do {
+        SkPMColor c = SkPixel4444ToPixel32(*s++);
+        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
+                               SkGetPackedB32(c));
+    } while (--width != 0);
+}
+
+static void ToColor_S565(SkColor dst[], const void* src, int width,
+                         SkColorTable*) {
+    SkASSERT(width > 0);
+    const uint16_t* s = (const uint16_t*)src;
+    do {
+        uint16_t c = *s++;
+        *dst++ =  SkColorSetRGB(SkPacked16ToR32(c), SkPacked16ToG32(c),
+                                SkPacked16ToB32(c));
+    } while (--width != 0);
+}
+
+static void ToColor_SI8_Alpha(SkColor dst[], const void* src, int width,
+                              SkColorTable* ctable) {
+    SkASSERT(width > 0);
+    const uint8_t* s = (const uint8_t*)src;
+    const SkPMColor* colors = ctable->lockColors();
+    do {
+        *dst++ = SkUnPreMultiply::PMColorToColor(colors[*s++]);
+    } while (--width != 0);
+    ctable->unlockColors();
+}
+
+static void ToColor_SI8_Raw(SkColor dst[], const void* src, int width,
+                              SkColorTable* ctable) {
+    SkASSERT(width > 0);
+    const uint8_t* s = (const uint8_t*)src;
+    const SkPMColor* colors = ctable->lockColors();
+    do {
+        SkPMColor c = colors[*s++];
+        *dst++ = SkColorSetARGB(SkGetPackedA32(c), SkGetPackedR32(c),
+                                SkGetPackedG32(c), SkGetPackedB32(c));
+    } while (--width != 0);
+    ctable->unlockColors();
+}
+
+static void ToColor_SI8_Opaque(SkColor dst[], const void* src, int width,
+                               SkColorTable* ctable) {
+    SkASSERT(width > 0);
+    const uint8_t* s = (const uint8_t*)src;
+    const SkPMColor* colors = ctable->lockColors();
+    do {
+        SkPMColor c = colors[*s++];
+        *dst++ = SkColorSetRGB(SkGetPackedR32(c), SkGetPackedG32(c),
+                               SkGetPackedB32(c));
+    } while (--width != 0);
+    ctable->unlockColors();
+}
+
+// can return NULL
+static ToColorProc ChooseToColorProc(const SkBitmap& src, bool isPremultiplied) {
+    switch (src.config()) {
+        case SkBitmap::kARGB_8888_Config:
+            if (src.isOpaque()) return ToColor_S32_Opaque;
+            return isPremultiplied ? ToColor_S32_Alpha : ToColor_S32_Raw;
+        case SkBitmap::kARGB_4444_Config:
+            if (src.isOpaque()) return ToColor_S4444_Opaque;
+            return isPremultiplied ? ToColor_S4444_Alpha : ToColor_S4444_Raw;
+        case SkBitmap::kRGB_565_Config:
+            return ToColor_S565;
+        case SkBitmap::kIndex8_Config:
+            if (src.getColorTable() == NULL) {
+                return NULL;
+            }
+            if (src.isOpaque()) return ToColor_SI8_Opaque;
+            return isPremultiplied ? ToColor_SI8_Raw : ToColor_SI8_Alpha;
+        default:
+            break;
+    }
+    return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static int getPremulBitmapCreateFlags(bool isMutable) {
+    int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied;
+    if (isMutable) flags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
+    return flags;
+}
+
+static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
+                              jint offset, jint stride, jint width, jint height,
+                              jint configHandle, jboolean isMutable) {
+    SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);
+    if (NULL != jColors) {
+        size_t n = env->GetArrayLength(jColors);
+        if (n < SkAbs32(stride) * (size_t)height) {
+            doThrowAIOOBE(env);
+            return NULL;
+        }
+    }
+
+    // ARGB_4444 is a deprecated format, convert automatically to 8888
+    if (config == SkBitmap::kARGB_4444_Config) {
+        config = SkBitmap::kARGB_8888_Config;
+    }
+
+    SkBitmap bitmap;
+    bitmap.setConfig(config, width, height);
+
+    jbyteArray buff = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
+    if (NULL == buff) {
+        return NULL;
+    }
+
+    if (jColors != NULL) {
+        GraphicsJNI::SetPixels(env, jColors, offset, stride,
+                0, 0, width, height, bitmap, true);
+    }
+
+    return GraphicsJNI::createBitmap(env, new SkBitmap(bitmap), buff,
+            getPremulBitmapCreateFlags(isMutable), NULL, NULL);
+}
+
+static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
+                           jint dstConfigHandle, jboolean isMutable) {
+    const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);
+    SkBitmap::Config dstConfig = static_cast<SkBitmap::Config>(dstConfigHandle);
+    SkBitmap            result;
+    JavaPixelAllocator  allocator(env);
+
     if (!src->copyTo(&result, SkBitmapConfigToColorType(dstConfig), &allocator)) {
-        return NULL;

-    }

-    return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(),

-            getPremulBitmapCreateFlags(isMutable), NULL, NULL);

-}

-

-static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) {

-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-#ifdef USE_OPENGL_RENDERER

-    if (android::uirenderer::Caches::hasInstance()) {

-        android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);

-        return;

-    }

-#endif // USE_OPENGL_RENDERER

-    delete bitmap;

-}

-

-static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {

-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-#ifdef USE_OPENGL_RENDERER

-    if (android::uirenderer::Caches::hasInstance()) {

-        bool result;

-        result = android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);

-        return result ? JNI_TRUE : JNI_FALSE;

-    }

-#endif // USE_OPENGL_RENDERER

-    bitmap->setPixels(NULL, NULL);

-    return JNI_TRUE;

-}

-

-static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,

-        jint width, jint height, jint configHandle, jint allocSize) {

-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);    

-    if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) {

-        // done in native as there's no way to get BytesPerPixel in Java

-        doThrowIAE(env, "Bitmap not large enough to support new configuration");

-        return;

-    }

-    SkPixelRef* ref = bitmap->pixelRef();

-    SkSafeRef(ref);

-    bitmap->setConfig(config, width, height);

-    bitmap->setPixelRef(ref);

-

-    // notifyPixelsChanged will increment the generation ID even though the actual pixel data

-    // hasn't been touched. This signals the renderer that the bitmap (including width, height,

-    // and config) has changed.

-    ref->notifyPixelsChanged();

-    SkSafeUnref(ref);

-}

-

-// These must match the int values in Bitmap.java

-enum JavaEncodeFormat {

-    kJPEG_JavaEncodeFormat = 0,

-    kPNG_JavaEncodeFormat = 1,

-    kWEBP_JavaEncodeFormat = 2

-};

-

-static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,

-                                jint format, jint quality,

-                                jobject jstream, jbyteArray jstorage) {

-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    SkImageEncoder::Type fm;

-

-    switch (format) {

-    case kJPEG_JavaEncodeFormat:

-        fm = SkImageEncoder::kJPEG_Type;

-        break;

-    case kPNG_JavaEncodeFormat:

-        fm = SkImageEncoder::kPNG_Type;

-        break;

-    case kWEBP_JavaEncodeFormat:

-        fm = SkImageEncoder::kWEBP_Type;

-        break;

-    default:

-        return JNI_FALSE;

-    }

-

-    bool success = false;

-    if (NULL != bitmap) {

-        SkAutoLockPixels alp(*bitmap);

-

-        if (NULL == bitmap->getPixels()) {

-            return JNI_FALSE;

-        }

-

-        SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);

-        if (NULL == strm) {

-            return JNI_FALSE;

-        }

-

-        SkImageEncoder* encoder = SkImageEncoder::Create(fm);

-        if (NULL != encoder) {

-            success = encoder->encodeStream(strm, *bitmap, quality);

-            delete encoder;

-        }

-        delete strm;

-    }

-    return success ? JNI_TRUE : JNI_FALSE;

-}

-

-static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {

-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    bitmap->eraseColor(color);

-}

-

-static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {

-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    return static_cast<jint>(bitmap->rowBytes());

-}

-

-static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {

-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    return static_cast<jint>(bitmap->config());

-}

-

-static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {

-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    return static_cast<jint>(bitmap->getGenerationID());

-}

-

-static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {

-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    return !bitmap->isOpaque() ? JNI_TRUE : JNI_FALSE;

-}

-

-static void Bitmap_setAlphaAndPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,

-                                            jboolean hasAlpha, jboolean isPremul) {

-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    if (!hasAlpha) {

-        bitmap->setAlphaType(kOpaque_SkAlphaType);

-    } else if (isPremul) {

-        bitmap->setAlphaType(kPremul_SkAlphaType);

-    } else {

-        bitmap->setAlphaType(kUnpremul_SkAlphaType);

-    }

-}

-

-static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {

-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;

-}

-

-static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,

-                                jboolean hasMipMap) {

-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    bitmap->setHasHardwareMipMap(hasMipMap);

-}

-

-///////////////////////////////////////////////////////////////////////////////

-

-static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {

-    if (parcel == NULL) {

-        SkDebugf("-------- unparcel parcel is NULL\n");

-        return NULL;

-    }

-

-    android::Parcel* p = android::parcelForJavaObject(env, parcel);

-

-    const bool              isMutable = p->readInt32() != 0;

-    const SkBitmap::Config  config = (SkBitmap::Config)p->readInt32();

-    const int               width = p->readInt32();

-    const int               height = p->readInt32();

-    const int               rowBytes = p->readInt32();

-    const int               density = p->readInt32();

-

-    if (SkBitmap::kARGB_8888_Config != config &&

-            SkBitmap::kRGB_565_Config != config &&

-            SkBitmap::kARGB_4444_Config != config &&

-            SkBitmap::kIndex8_Config != config &&

-            SkBitmap::kA8_Config != config) {

-        SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);

-        return NULL;

-    }

-

-    SkBitmap* bitmap = new SkBitmap;

-

-    bitmap->setConfig(config, width, height, rowBytes);

-

-    SkColorTable* ctable = NULL;

-    if (config == SkBitmap::kIndex8_Config) {

-        int count = p->readInt32();

-        if (count > 0) {

-            size_t size = count * sizeof(SkPMColor);

-            const SkPMColor* src = (const SkPMColor*)p->readInplace(size);

-            ctable = new SkColorTable(src, count);

-        }

-    }

-

-    jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);

-    if (NULL == buffer) {

-        SkSafeUnref(ctable);

-        delete bitmap;

-        return NULL;

-    }

-

-    SkSafeUnref(ctable);

-

-    size_t size = bitmap->getSize();

-

-    android::Parcel::ReadableBlob blob;

-    android::status_t status = p->readBlob(size, &blob);

-    if (status) {

-        doThrowRE(env, "Could not read bitmap from parcel blob.");

-        delete bitmap;

-        return NULL;

-    }

-

-    bitmap->lockPixels();

-    memcpy(bitmap->getPixels(), blob.data(), size);

-    bitmap->unlockPixels();

-

-    blob.release();

-

-    return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable),

-            NULL, NULL, density);

-}

-

-static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,

-                                     jlong bitmapHandle,

-                                     jboolean isMutable, jint density,

-                                     jobject parcel) {

-    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    if (parcel == NULL) {

-        SkDebugf("------- writeToParcel null parcel\n");

-        return JNI_FALSE;

-    }

-

-    android::Parcel* p = android::parcelForJavaObject(env, parcel);

-

-    p->writeInt32(isMutable);

-    p->writeInt32(bitmap->config());

-    p->writeInt32(bitmap->width());

-    p->writeInt32(bitmap->height());

-    p->writeInt32(bitmap->rowBytes());

-    p->writeInt32(density);

-

-    if (bitmap->config() == SkBitmap::kIndex8_Config) {

-        SkColorTable* ctable = bitmap->getColorTable();

-        if (ctable != NULL) {

-            int count = ctable->count();

-            p->writeInt32(count);

-            memcpy(p->writeInplace(count * sizeof(SkPMColor)),

-                   ctable->lockColors(), count * sizeof(SkPMColor));

-            ctable->unlockColors();

-        } else {

-            p->writeInt32(0);   // indicate no ctable

-        }

-    }

-

-    size_t size = bitmap->getSize();

-

-    android::Parcel::WritableBlob blob;

-    android::status_t status = p->writeBlob(size, &blob);

-    if (status) {

-        doThrowRE(env, "Could not write bitmap to parcel blob.");

-        return JNI_FALSE;

-    }

-

-    bitmap->lockPixels();

-    const void* pSrc =  bitmap->getPixels();

-    if (pSrc == NULL) {

-        memset(blob.data(), 0, size);

-    } else {

-        memcpy(blob.data(), pSrc, size);

-    }

-    bitmap->unlockPixels();

-

-    blob.release();

-    return JNI_TRUE;

-}

-

-static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,

-                                   jlong srcHandle, jlong paintHandle,

-                                   jintArray offsetXY) {

-    const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);

-    const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);

-    SkIPoint  offset;

-    SkBitmap* dst = new SkBitmap;

-    JavaPixelAllocator allocator(env);

-

-    src->extractAlpha(dst, paint, &allocator, &offset);

-    // If Skia can't allocate pixels for destination bitmap, it resets

-    // it, that is set its pixels buffer to NULL, and zero width and height.

-    if (dst->getPixels() == NULL && src->getPixels() != NULL) {

-        delete dst;

-        doThrowOOME(env, "failed to allocate pixels for alpha");

-        return NULL;

-    }

-    if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {

-        int* array = env->GetIntArrayElements(offsetXY, NULL);

-        array[0] = offset.fX;

-        array[1] = offset.fY;

-        env->ReleaseIntArrayElements(offsetXY, array, 0);

-    }

-

-    return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(),

-            getPremulBitmapCreateFlags(true), NULL, NULL);

-}

-

-///////////////////////////////////////////////////////////////////////////////

-

-static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,

-        jint x, jint y, jboolean isPremultiplied) {

-    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    SkAutoLockPixels alp(*bitmap);

-

-    ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);

-    if (NULL == proc) {

-        return 0;

-    }

-    const void* src = bitmap->getAddr(x, y);

-    if (NULL == src) {

-        return 0;

-    }

-

-    SkColor dst[1];

-    proc(dst, src, 1, bitmap->getColorTable());

-    return static_cast<jint>(dst[0]);

-}

-

-static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,

-        jintArray pixelArray, jint offset, jint stride,

-        jint x, jint y, jint width, jint height, jboolean isPremultiplied) {

-    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    SkAutoLockPixels alp(*bitmap);

-

-    ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);

-    if (NULL == proc) {

-        return;

-    }

-    const void* src = bitmap->getAddr(x, y);

-    if (NULL == src) {

-        return;

-    }

-

-    SkColorTable* ctable = bitmap->getColorTable();

-    jint* dst = env->GetIntArrayElements(pixelArray, NULL);

-    SkColor* d = (SkColor*)dst + offset;

-    while (--height >= 0) {

-        proc(d, src, width, ctable);

-        d += stride;

-        src = (void*)((const char*)src + bitmap->rowBytes());

-    }

-    env->ReleaseIntArrayElements(pixelArray, dst, 0);

-}

-

-///////////////////////////////////////////////////////////////////////////////

-

-static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,

-        jint x, jint y, jint colorHandle, jboolean isPremultiplied) {

-    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    SkColor color = static_cast<SkColor>(colorHandle);

-    SkAutoLockPixels alp(*bitmap);

-    if (NULL == bitmap->getPixels()) {

-        return;

-    }

-

-    FromColorProc proc = ChooseFromColorProc(bitmap->config(), isPremultiplied);

-    if (NULL == proc) {

-        return;

-    }

-

-    proc(bitmap->getAddr(x, y), &color, 1, x, y);

-    bitmap->notifyPixelsChanged();

-}

-

-static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,

-        jintArray pixelArray, jint offset, jint stride,

-        jint x, jint y, jint width, jint height, jboolean isPremultiplied) {

-    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    GraphicsJNI::SetPixels(env, pixelArray, offset, stride,

-            x, y, width, height, *bitmap, isPremultiplied);

-}

-

-static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,

-                                      jlong bitmapHandle, jobject jbuffer) {

-    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    SkAutoLockPixels alp(*bitmap);

-    const void* src = bitmap->getPixels();

-

-    if (NULL != src) {

-        android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);

-

-        // the java side has already checked that buffer is large enough

-        memcpy(abp.pointer(), src, bitmap->getSize());

-    }

-}

-

-static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,

-                                        jlong bitmapHandle, jobject jbuffer) {

-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    SkAutoLockPixels alp(*bitmap);

-    void* dst = bitmap->getPixels();

-

-    if (NULL != dst) {

-        android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);

-        // the java side has already checked that buffer is large enough

-        memcpy(dst, abp.pointer(), bitmap->getSize());

-        bitmap->notifyPixelsChanged();

-    }

-}

-

-static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle,

-                              jlong bm1Handle) {

-    const SkBitmap* bm0 = reinterpret_cast<SkBitmap*>(bm0Handle);

-    const SkBitmap* bm1 = reinterpret_cast<SkBitmap*>(bm1Handle);

-    if (bm0->width() != bm1->width() ||

-        bm0->height() != bm1->height() ||

-        bm0->config() != bm1->config()) {

-        return JNI_FALSE;

-    }

-

-    SkAutoLockPixels alp0(*bm0);

-    SkAutoLockPixels alp1(*bm1);

-

-    // if we can't load the pixels, return false

-    if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) {

-        return JNI_FALSE;

-    }

-

-    if (bm0->config() == SkBitmap::kIndex8_Config) {

-        SkColorTable* ct0 = bm0->getColorTable();

-        SkColorTable* ct1 = bm1->getColorTable();

-        if (NULL == ct0 || NULL == ct1) {

-            return JNI_FALSE;

-        }

-        if (ct0->count() != ct1->count()) {

-            return JNI_FALSE;

-        }

-

-        SkAutoLockColors alc0(ct0);

-        SkAutoLockColors alc1(ct1);

-        const size_t size = ct0->count() * sizeof(SkPMColor);

-        if (memcmp(alc0.colors(), alc1.colors(), size) != 0) {

-            return JNI_FALSE;

-        }

-    }

-

-    // now compare each scanline. We can't do the entire buffer at once,

-    // since we don't care about the pixel values that might extend beyond

-    // the width (since the scanline might be larger than the logical width)

-    const int h = bm0->height();

-    const size_t size = bm0->width() * bm0->bytesPerPixel();

-    for (int y = 0; y < h; y++) {

-        if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) {

-            return JNI_FALSE;

-        }

-    }

-    return JNI_TRUE;

-}

-

-static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapHandle) {

-    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);

-    bitmap->lockPixels();

-    bitmap->unlockPixels();

-}

-

-///////////////////////////////////////////////////////////////////////////////

-

-#include <android_runtime/AndroidRuntime.h>

-

-static JNINativeMethod gBitmapMethods[] = {

-    {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",

-        (void*)Bitmap_creator },

-    {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",

-        (void*)Bitmap_copy },

-    {   "nativeDestructor",         "(J)V", (void*)Bitmap_destructor },

-    {   "nativeRecycle",            "(J)Z", (void*)Bitmap_recycle },

-    {   "nativeReconfigure",        "(JIIII)V", (void*)Bitmap_reconfigure },

-    {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",

-        (void*)Bitmap_compress },

-    {   "nativeErase",              "(JI)V", (void*)Bitmap_erase },

-    {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },

-    {   "nativeConfig",             "(J)I", (void*)Bitmap_config },

-    {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },

-    {   "nativeSetAlphaAndPremultiplied", "(JZZ)V", (void*)Bitmap_setAlphaAndPremultiplied},

-    {   "nativeHasMipMap",          "(J)Z", (void*)Bitmap_hasMipMap },

-    {   "nativeSetHasMipMap",       "(JZ)V", (void*)Bitmap_setHasMipMap },

-    {   "nativeCreateFromParcel",

-        "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",

-        (void*)Bitmap_createFromParcel },

-    {   "nativeWriteToParcel",      "(JZILandroid/os/Parcel;)Z",

-        (void*)Bitmap_writeToParcel },

-    {   "nativeExtractAlpha",       "(JJ[I)Landroid/graphics/Bitmap;",

-        (void*)Bitmap_extractAlpha },

-    {   "nativeGenerationId",       "(J)I", (void*)Bitmap_getGenerationId },

-    {   "nativeGetPixel",           "(JIIZ)I", (void*)Bitmap_getPixel },

-    {   "nativeGetPixels",          "(J[IIIIIIIZ)V", (void*)Bitmap_getPixels },

-    {   "nativeSetPixel",           "(JIIIZ)V", (void*)Bitmap_setPixel },

-    {   "nativeSetPixels",          "(J[IIIIIIIZ)V", (void*)Bitmap_setPixels },

-    {   "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",

-                                            (void*)Bitmap_copyPixelsToBuffer },

-    {   "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",

-                                            (void*)Bitmap_copyPixelsFromBuffer },

-    {   "nativeSameAs",             "(JJ)Z", (void*)Bitmap_sameAs },

-    {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },

-};

-

-#define kClassPathName  "android/graphics/Bitmap"

-

-int register_android_graphics_Bitmap(JNIEnv* env)

-{

-    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,

-                                gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));

-}

+        return NULL;
+    }
+    return GraphicsJNI::createBitmap(env, new SkBitmap(result), allocator.getStorageObj(),
+            getPremulBitmapCreateFlags(isMutable), NULL, NULL);
+}
+
+static void Bitmap_destructor(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+#ifdef USE_OPENGL_RENDERER
+    if (android::uirenderer::Caches::hasInstance()) {
+        android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);
+        return;
+    }
+#endif // USE_OPENGL_RENDERER
+    delete bitmap;
+}
+
+static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+#ifdef USE_OPENGL_RENDERER
+    if (android::uirenderer::Caches::hasInstance()) {
+        bool result;
+        result = android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);
+        return result ? JNI_TRUE : JNI_FALSE;
+    }
+#endif // USE_OPENGL_RENDERER
+    bitmap->setPixels(NULL, NULL);
+    return JNI_TRUE;
+}
+
+static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
+        jint width, jint height, jint configHandle, jint allocSize) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkBitmap::Config config = static_cast<SkBitmap::Config>(configHandle);
+    if (width * height * SkBitmap::ComputeBytesPerPixel(config) > allocSize) {
+        // done in native as there's no way to get BytesPerPixel in Java
+        doThrowIAE(env, "Bitmap not large enough to support new configuration");
+        return;
+    }
+    SkPixelRef* ref = bitmap->pixelRef();
+    SkSafeRef(ref);
+    bitmap->setConfig(config, width, height);
+    bitmap->setPixelRef(ref);
+
+    // notifyPixelsChanged will increment the generation ID even though the actual pixel data
+    // hasn't been touched. This signals the renderer that the bitmap (including width, height,
+    // and config) has changed.
+    ref->notifyPixelsChanged();
+    SkSafeUnref(ref);
+}
+
+// These must match the int values in Bitmap.java
+enum JavaEncodeFormat {
+    kJPEG_JavaEncodeFormat = 0,
+    kPNG_JavaEncodeFormat = 1,
+    kWEBP_JavaEncodeFormat = 2
+};
+
+static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
+                                jint format, jint quality,
+                                jobject jstream, jbyteArray jstorage) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkImageEncoder::Type fm;
+
+    switch (format) {
+    case kJPEG_JavaEncodeFormat:
+        fm = SkImageEncoder::kJPEG_Type;
+        break;
+    case kPNG_JavaEncodeFormat:
+        fm = SkImageEncoder::kPNG_Type;
+        break;
+    case kWEBP_JavaEncodeFormat:
+        fm = SkImageEncoder::kWEBP_Type;
+        break;
+    default:
+        return JNI_FALSE;
+    }
+
+    bool success = false;
+    if (NULL != bitmap) {
+        SkAutoLockPixels alp(*bitmap);
+
+        if (NULL == bitmap->getPixels()) {
+            return JNI_FALSE;
+        }
+
+        SkWStream* strm = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
+        if (NULL == strm) {
+            return JNI_FALSE;
+        }
+
+        SkImageEncoder* encoder = SkImageEncoder::Create(fm);
+        if (NULL != encoder) {
+            success = encoder->encodeStream(strm, *bitmap, quality);
+            delete encoder;
+        }
+        delete strm;
+    }
+    return success ? JNI_TRUE : JNI_FALSE;
+}
+
+static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    bitmap->eraseColor(color);
+}
+
+static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    return static_cast<jint>(bitmap->rowBytes());
+}
+
+static jint Bitmap_config(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    return static_cast<jint>(bitmap->config());
+}
+
+static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    return static_cast<jint>(bitmap->getGenerationID());
+}
+
+static jboolean Bitmap_hasAlpha(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    return !bitmap->isOpaque() ? JNI_TRUE : JNI_FALSE;
+}
+
+static void Bitmap_setAlphaAndPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle,
+                                            jboolean hasAlpha, jboolean isPremul) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    if (!hasAlpha) {
+        bitmap->setAlphaType(kOpaque_SkAlphaType);
+    } else if (isPremul) {
+        bitmap->setAlphaType(kPremul_SkAlphaType);
+    } else {
+        bitmap->setAlphaType(kUnpremul_SkAlphaType);
+    }
+}
+
+static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    return bitmap->hasHardwareMipMap() ? JNI_TRUE : JNI_FALSE;
+}
+
+static void Bitmap_setHasMipMap(JNIEnv* env, jobject, jlong bitmapHandle,
+                                jboolean hasMipMap) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    bitmap->setHasHardwareMipMap(hasMipMap);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
+    if (parcel == NULL) {
+        SkDebugf("-------- unparcel parcel is NULL\n");
+        return NULL;
+    }
+
+    android::Parcel* p = android::parcelForJavaObject(env, parcel);
+
+    const bool              isMutable = p->readInt32() != 0;
+    const SkBitmap::Config  config = (SkBitmap::Config)p->readInt32();
+    const int               width = p->readInt32();
+    const int               height = p->readInt32();
+    const int               rowBytes = p->readInt32();
+    const int               density = p->readInt32();
+
+    if (SkBitmap::kARGB_8888_Config != config &&
+            SkBitmap::kRGB_565_Config != config &&
+            SkBitmap::kARGB_4444_Config != config &&
+            SkBitmap::kIndex8_Config != config &&
+            SkBitmap::kA8_Config != config) {
+        SkDebugf("Bitmap_createFromParcel unknown config: %d\n", config);
+        return NULL;
+    }
+
+    SkBitmap* bitmap = new SkBitmap;
+
+    bitmap->setConfig(config, width, height, rowBytes);
+
+    SkColorTable* ctable = NULL;
+    if (config == SkBitmap::kIndex8_Config) {
+        int count = p->readInt32();
+        if (count > 0) {
+            size_t size = count * sizeof(SkPMColor);
+            const SkPMColor* src = (const SkPMColor*)p->readInplace(size);
+            ctable = new SkColorTable(src, count);
+        }
+    }
+
+    jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
+    if (NULL == buffer) {
+        SkSafeUnref(ctable);
+        delete bitmap;
+        return NULL;
+    }
+
+    SkSafeUnref(ctable);
+
+    size_t size = bitmap->getSize();
+
+    android::Parcel::ReadableBlob blob;
+    android::status_t status = p->readBlob(size, &blob);
+    if (status) {
+        doThrowRE(env, "Could not read bitmap from parcel blob.");
+        delete bitmap;
+        return NULL;
+    }
+
+    bitmap->lockPixels();
+    memcpy(bitmap->getPixels(), blob.data(), size);
+    bitmap->unlockPixels();
+
+    blob.release();
+
+    return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable),
+            NULL, NULL, density);
+}
+
+static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,
+                                     jlong bitmapHandle,
+                                     jboolean isMutable, jint density,
+                                     jobject parcel) {
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    if (parcel == NULL) {
+        SkDebugf("------- writeToParcel null parcel\n");
+        return JNI_FALSE;
+    }
+
+    android::Parcel* p = android::parcelForJavaObject(env, parcel);
+
+    p->writeInt32(isMutable);
+    p->writeInt32(bitmap->config());
+    p->writeInt32(bitmap->width());
+    p->writeInt32(bitmap->height());
+    p->writeInt32(bitmap->rowBytes());
+    p->writeInt32(density);
+
+    if (bitmap->config() == SkBitmap::kIndex8_Config) {
+        SkColorTable* ctable = bitmap->getColorTable();
+        if (ctable != NULL) {
+            int count = ctable->count();
+            p->writeInt32(count);
+            memcpy(p->writeInplace(count * sizeof(SkPMColor)),
+                   ctable->lockColors(), count * sizeof(SkPMColor));
+            ctable->unlockColors();
+        } else {
+            p->writeInt32(0);   // indicate no ctable
+        }
+    }
+
+    size_t size = bitmap->getSize();
+
+    android::Parcel::WritableBlob blob;
+    android::status_t status = p->writeBlob(size, &blob);
+    if (status) {
+        doThrowRE(env, "Could not write bitmap to parcel blob.");
+        return JNI_FALSE;
+    }
+
+    bitmap->lockPixels();
+    const void* pSrc =  bitmap->getPixels();
+    if (pSrc == NULL) {
+        memset(blob.data(), 0, size);
+    } else {
+        memcpy(blob.data(), pSrc, size);
+    }
+    bitmap->unlockPixels();
+
+    blob.release();
+    return JNI_TRUE;
+}
+
+static jobject Bitmap_extractAlpha(JNIEnv* env, jobject clazz,
+                                   jlong srcHandle, jlong paintHandle,
+                                   jintArray offsetXY) {
+    const SkBitmap* src = reinterpret_cast<SkBitmap*>(srcHandle);
+    const SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+    SkIPoint  offset;
+    SkBitmap* dst = new SkBitmap;
+    JavaPixelAllocator allocator(env);
+
+    src->extractAlpha(dst, paint, &allocator, &offset);
+    // If Skia can't allocate pixels for destination bitmap, it resets
+    // it, that is set its pixels buffer to NULL, and zero width and height.
+    if (dst->getPixels() == NULL && src->getPixels() != NULL) {
+        delete dst;
+        doThrowOOME(env, "failed to allocate pixels for alpha");
+        return NULL;
+    }
+    if (offsetXY != 0 && env->GetArrayLength(offsetXY) >= 2) {
+        int* array = env->GetIntArrayElements(offsetXY, NULL);
+        array[0] = offset.fX;
+        array[1] = offset.fY;
+        env->ReleaseIntArrayElements(offsetXY, array, 0);
+    }
+
+    return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(),
+            getPremulBitmapCreateFlags(true), NULL, NULL);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static jint Bitmap_getPixel(JNIEnv* env, jobject, jlong bitmapHandle,
+        jint x, jint y, jboolean isPremultiplied) {
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkAutoLockPixels alp(*bitmap);
+
+    ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
+    if (NULL == proc) {
+        return 0;
+    }
+    const void* src = bitmap->getAddr(x, y);
+    if (NULL == src) {
+        return 0;
+    }
+
+    SkColor dst[1];
+    proc(dst, src, 1, bitmap->getColorTable());
+    return static_cast<jint>(dst[0]);
+}
+
+static void Bitmap_getPixels(JNIEnv* env, jobject, jlong bitmapHandle,
+        jintArray pixelArray, jint offset, jint stride,
+        jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkAutoLockPixels alp(*bitmap);
+
+    ToColorProc proc = ChooseToColorProc(*bitmap, isPremultiplied);
+    if (NULL == proc) {
+        return;
+    }
+    const void* src = bitmap->getAddr(x, y);
+    if (NULL == src) {
+        return;
+    }
+
+    SkColorTable* ctable = bitmap->getColorTable();
+    jint* dst = env->GetIntArrayElements(pixelArray, NULL);
+    SkColor* d = (SkColor*)dst + offset;
+    while (--height >= 0) {
+        proc(d, src, width, ctable);
+        d += stride;
+        src = (void*)((const char*)src + bitmap->rowBytes());
+    }
+    env->ReleaseIntArrayElements(pixelArray, dst, 0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void Bitmap_setPixel(JNIEnv* env, jobject, jlong bitmapHandle,
+        jint x, jint y, jint colorHandle, jboolean isPremultiplied) {
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkColor color = static_cast<SkColor>(colorHandle);
+    SkAutoLockPixels alp(*bitmap);
+    if (NULL == bitmap->getPixels()) {
+        return;
+    }
+
+    FromColorProc proc = ChooseFromColorProc(bitmap->config(), isPremultiplied);
+    if (NULL == proc) {
+        return;
+    }
+
+    proc(bitmap->getAddr(x, y), &color, 1, x, y);
+    bitmap->notifyPixelsChanged();
+}
+
+static void Bitmap_setPixels(JNIEnv* env, jobject, jlong bitmapHandle,
+        jintArray pixelArray, jint offset, jint stride,
+        jint x, jint y, jint width, jint height, jboolean isPremultiplied) {
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    GraphicsJNI::SetPixels(env, pixelArray, offset, stride,
+            x, y, width, height, *bitmap, isPremultiplied);
+}
+
+static void Bitmap_copyPixelsToBuffer(JNIEnv* env, jobject,
+                                      jlong bitmapHandle, jobject jbuffer) {
+    const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkAutoLockPixels alp(*bitmap);
+    const void* src = bitmap->getPixels();
+
+    if (NULL != src) {
+        android::AutoBufferPointer abp(env, jbuffer, JNI_TRUE);
+
+        // the java side has already checked that buffer is large enough
+        memcpy(abp.pointer(), src, bitmap->getSize());
+    }
+}
+
+static void Bitmap_copyPixelsFromBuffer(JNIEnv* env, jobject,
+                                        jlong bitmapHandle, jobject jbuffer) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    SkAutoLockPixels alp(*bitmap);
+    void* dst = bitmap->getPixels();
+
+    if (NULL != dst) {
+        android::AutoBufferPointer abp(env, jbuffer, JNI_FALSE);
+        // the java side has already checked that buffer is large enough
+        memcpy(dst, abp.pointer(), bitmap->getSize());
+        bitmap->notifyPixelsChanged();
+    }
+}
+
+static jboolean Bitmap_sameAs(JNIEnv* env, jobject, jlong bm0Handle,
+                              jlong bm1Handle) {
+    const SkBitmap* bm0 = reinterpret_cast<SkBitmap*>(bm0Handle);
+    const SkBitmap* bm1 = reinterpret_cast<SkBitmap*>(bm1Handle);
+    if (bm0->width() != bm1->width() ||
+        bm0->height() != bm1->height() ||
+        bm0->config() != bm1->config()) {
+        return JNI_FALSE;
+    }
+
+    SkAutoLockPixels alp0(*bm0);
+    SkAutoLockPixels alp1(*bm1);
+
+    // if we can't load the pixels, return false
+    if (NULL == bm0->getPixels() || NULL == bm1->getPixels()) {
+        return JNI_FALSE;
+    }
+
+    if (bm0->config() == SkBitmap::kIndex8_Config) {
+        SkColorTable* ct0 = bm0->getColorTable();
+        SkColorTable* ct1 = bm1->getColorTable();
+        if (NULL == ct0 || NULL == ct1) {
+            return JNI_FALSE;
+        }
+        if (ct0->count() != ct1->count()) {
+            return JNI_FALSE;
+        }
+
+        SkAutoLockColors alc0(ct0);
+        SkAutoLockColors alc1(ct1);
+        const size_t size = ct0->count() * sizeof(SkPMColor);
+        if (memcmp(alc0.colors(), alc1.colors(), size) != 0) {
+            return JNI_FALSE;
+        }
+    }
+
+    // now compare each scanline. We can't do the entire buffer at once,
+    // since we don't care about the pixel values that might extend beyond
+    // the width (since the scanline might be larger than the logical width)
+    const int h = bm0->height();
+    const size_t size = bm0->width() * bm0->bytesPerPixel();
+    for (int y = 0; y < h; y++) {
+        if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) {
+            return JNI_FALSE;
+        }
+    }
+    return JNI_TRUE;
+}
+
+static void Bitmap_prepareToDraw(JNIEnv* env, jobject, jlong bitmapHandle) {
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
+    bitmap->lockPixels();
+    bitmap->unlockPixels();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include <android_runtime/AndroidRuntime.h>
+
+static JNINativeMethod gBitmapMethods[] = {
+    {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",
+        (void*)Bitmap_creator },
+    {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",
+        (void*)Bitmap_copy },
+    {   "nativeDestructor",         "(J)V", (void*)Bitmap_destructor },
+    {   "nativeRecycle",            "(J)Z", (void*)Bitmap_recycle },
+    {   "nativeReconfigure",        "(JIIII)V", (void*)Bitmap_reconfigure },
+    {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
+        (void*)Bitmap_compress },
+    {   "nativeErase",              "(JI)V", (void*)Bitmap_erase },
+    {   "nativeRowBytes",           "(J)I", (void*)Bitmap_rowBytes },
+    {   "nativeConfig",             "(J)I", (void*)Bitmap_config },
+    {   "nativeHasAlpha",           "(J)Z", (void*)Bitmap_hasAlpha },
+    {   "nativeSetAlphaAndPremultiplied", "(JZZ)V", (void*)Bitmap_setAlphaAndPremultiplied},
+    {   "nativeHasMipMap",          "(J)Z", (void*)Bitmap_hasMipMap },
+    {   "nativeSetHasMipMap",       "(JZ)V", (void*)Bitmap_setHasMipMap },
+    {   "nativeCreateFromParcel",
+        "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",
+        (void*)Bitmap_createFromParcel },
+    {   "nativeWriteToParcel",      "(JZILandroid/os/Parcel;)Z",
+        (void*)Bitmap_writeToParcel },
+    {   "nativeExtractAlpha",       "(JJ[I)Landroid/graphics/Bitmap;",
+        (void*)Bitmap_extractAlpha },
+    {   "nativeGenerationId",       "(J)I", (void*)Bitmap_getGenerationId },
+    {   "nativeGetPixel",           "(JIIZ)I", (void*)Bitmap_getPixel },
+    {   "nativeGetPixels",          "(J[IIIIIIIZ)V", (void*)Bitmap_getPixels },
+    {   "nativeSetPixel",           "(JIIIZ)V", (void*)Bitmap_setPixel },
+    {   "nativeSetPixels",          "(J[IIIIIIIZ)V", (void*)Bitmap_setPixels },
+    {   "nativeCopyPixelsToBuffer", "(JLjava/nio/Buffer;)V",
+                                            (void*)Bitmap_copyPixelsToBuffer },
+    {   "nativeCopyPixelsFromBuffer", "(JLjava/nio/Buffer;)V",
+                                            (void*)Bitmap_copyPixelsFromBuffer },
+    {   "nativeSameAs",             "(JJ)Z", (void*)Bitmap_sameAs },
+    {   "nativePrepareToDraw",      "(J)V", (void*)Bitmap_prepareToDraw },
+};
+
+#define kClassPathName  "android/graphics/Bitmap"
+
+int register_android_graphics_Bitmap(JNIEnv* env)
+{
+    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
+                                gBitmapMethods, SK_ARRAY_COUNT(gBitmapMethods));
+}
diff --git a/core/jni/android/graphics/CanvasProperty.cpp b/core/jni/android/graphics/CanvasProperty.cpp
index 70e2db5..cfa9cd8 100644
--- a/core/jni/android/graphics/CanvasProperty.cpp
+++ b/core/jni/android/graphics/CanvasProperty.cpp
@@ -18,7 +18,7 @@
 #include "GraphicsJNI.h"
 #include <android_runtime/AndroidRuntime.h>
 
-#include <utils/VirtualLightRefBase.h>
+#include <utils/RefBase.h>
 #include <CanvasProperty.h>
 
 namespace android {
@@ -27,22 +27,13 @@
 
 #ifdef USE_OPENGL_RENDERER
 
-static jlong incRef(VirtualLightRefBase* ptr) {
-    ptr->incStrong(0);
-    return reinterpret_cast<jlong>(ptr);
-}
-
 static jlong createFloat(JNIEnv* env, jobject clazz, jfloat initialValue) {
-    return incRef(new CanvasPropertyPrimitive(initialValue));
+    return reinterpret_cast<jlong>(new CanvasPropertyPrimitive(initialValue));
 }
 
 static jlong createPaint(JNIEnv* env, jobject clazz, jlong paintPtr) {
     const SkPaint* paint = reinterpret_cast<const SkPaint*>(paintPtr);
-    return incRef(new CanvasPropertyPaint(*paint));
-}
-
-static void unref(JNIEnv* env, jobject clazz, jlong containerPtr) {
-    reinterpret_cast<VirtualLightRefBase*>(containerPtr)->decStrong(0);
+    return reinterpret_cast<jlong>(new CanvasPropertyPaint(*paint));
 }
 
 #endif
@@ -57,7 +48,6 @@
 #ifdef USE_OPENGL_RENDERER
     { "nCreateFloat", "(F)J", (void*) createFloat },
     { "nCreatePaint", "(J)J", (void*) createPaint },
-    { "nUnref", "(J)V", (void*) unref },
 #endif
 };
 
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 08a88d1..22c17dd 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -33,6 +33,7 @@
 #include "SkXfermode.h"
 #include "unicode/uloc.h"
 #include "unicode/ushape.h"
+#include "utils/Blur.h"
 #include "TextLayout.h"
 
 // temporary for debugging
@@ -776,19 +777,23 @@
         env->ReleaseStringChars(text, textArray);
     }
 
-    static void setShadowLayer(JNIEnv* env, jobject jpaint, jfloat radius,
+    static void setShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat radius,
                                jfloat dx, jfloat dy, jint color) {
-        NPE_CHECK_RETURN_VOID(env, jpaint);
-
-        SkPaint* paint = GraphicsJNI::getNativePaint(env, jpaint);
+        SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
         if (radius <= 0) {
             paint->setLooper(NULL);
         }
         else {
-            paint->setLooper(new SkBlurDrawLooper(radius, dx, dy, (SkColor)color))->unref();
+            SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
+            paint->setLooper(new SkBlurDrawLooper((SkColor)color, sigma, dx, dy))->unref();
         }
     }
 
+    static jboolean hasShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle) {
+        SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle);
+        return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL);
+    }
+
     static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[],
                          int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
                          SkPaint::TextBufferDirection tbd) {
@@ -968,7 +973,8 @@
                                         (void*) SkPaintGlue::getStringBounds },
     {"nativeGetCharArrayBounds", "(J[CIIILandroid/graphics/Rect;)V",
                                     (void*) SkPaintGlue::getCharArrayBounds },
-    {"nSetShadowLayer", "(FFFI)V", (void*)SkPaintGlue::setShadowLayer}
+    {"native_setShadowLayer", "(JFFFI)V", (void*)SkPaintGlue::setShadowLayer},
+    {"native_hasShadowLayer", "(J)Z", (void*)SkPaintGlue::hasShadowLayer}
 };
 
 static jfieldID req_fieldID(jfieldID id) {
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index da752752..463a0a8 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -526,12 +526,15 @@
         switch (format) {
 
         default:
-            // TODO Currently the only possible values for format are AUDIO_FORMAT_PCM_16_BIT
-            // and AUDIO_FORMAT_PCM_8_BIT, due to the limited set of values for audioFormat.
+            // TODO Currently the only possible values for format are AUDIO_FORMAT_PCM_16_BIT,
+            // AUDIO_FORMAT_PCM_8_BIT, and AUDIO_FORMAT_PCM_FLOAT,
+            // due to the limited set of values for audioFormat.
             // The next section of the switch will probably work for more formats, but it has only
-            // been tested for AUDIO_FORMAT_PCM_16_BIT, so that's why the "default" case fails.
+            // been tested for AUDIO_FORMAT_PCM_16_BIT and AUDIO_FORMAT_PCM_FLOAT,
+            // so that's why the "default" case fails.
             break;
 
+        case AUDIO_FORMAT_PCM_FLOAT:
         case AUDIO_FORMAT_PCM_16_BIT: {
             // writing to shared memory, check for capacity
             if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
@@ -679,6 +682,44 @@
 
 
 // ----------------------------------------------------------------------------
+static jint android_media_AudioTrack_write_float(JNIEnv *env,  jobject thiz,
+                                                  jfloatArray javaAudioData,
+                                                  jint offsetInFloats, jint sizeInFloats,
+                                                  jint javaAudioFormat,
+                                                  jboolean isWriteBlocking) {
+
+    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+    if (lpTrack == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioTrack pointer for write()");
+        return 0;
+    }
+
+    jfloat* cAudioData = NULL;
+    if (javaAudioData) {
+        cAudioData = (jfloat *)env->GetFloatArrayElements(javaAudioData, NULL);
+        if (cAudioData == NULL) {
+            ALOGE("Error retrieving source of audio data to play, can't play");
+            return 0; // out of memory or no data to load
+        }
+    } else {
+        ALOGE("NULL java array of audio data to play, can't play");
+        return 0;
+    }
+    jint written = writeToTrack(lpTrack, javaAudioFormat, (jbyte *)cAudioData,
+                                offsetInFloats * sizeof(float), sizeInFloats * sizeof(float),
+                                isWriteBlocking == JNI_TRUE /* blocking */);
+    env->ReleaseFloatArrayElements(javaAudioData, cAudioData, 0);
+
+    if (written > 0) {
+        written /= sizeof(float);
+    }
+
+    return written;
+}
+
+
+// ----------------------------------------------------------------------------
 static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env,  jobject thiz) {
     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
     if (lpTrack == NULL) {
@@ -963,6 +1004,7 @@
                              "(Ljava/lang/Object;IIIZ)I",
                                          (void *)android_media_AudioTrack_write_native_bytes},
     {"native_write_short",   "([SIII)I", (void *)android_media_AudioTrack_write_short},
+    {"native_write_float",   "([FIIIZ)I",(void *)android_media_AudioTrack_write_float},
     {"native_setVolume",     "(FF)V",    (void *)android_media_AudioTrack_set_volume},
     {"native_get_native_frame_count",
                              "()I",      (void *)android_media_AudioTrack_get_native_frame_count},
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 3aa179d..fae6698 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -79,7 +79,6 @@
     #define RENDERER_LOGD(...)
 #endif
 
-#define MODIFIER_SHADOW 1
 #define MODIFIER_SHADER 2
 
 // ----------------------------------------------------------------------------
@@ -206,32 +205,6 @@
     return renderer->callDrawGLFunction(functor, dirty);
 }
 
-static void android_view_GLES20Canvas_detachFunctor(JNIEnv* env,
-        jobject clazz, jlong rendererPtr, jlong functorPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
-    renderer->detachFunctor(functor);
-}
-
-static void android_view_GLES20Canvas_attachFunctor(JNIEnv* env,
-        jobject clazz, jlong rendererPtr, jlong functorPtr) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
-    renderer->attachFunctor(functor);
-}
-
-static jint android_view_GLES20Canvas_invokeFunctors(JNIEnv* env,
-        jobject clazz, jlong rendererPtr, jobject dirty) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    android::uirenderer::Rect bounds;
-    status_t status = renderer->invokeFunctors(bounds);
-    if (status != DrawGlInfo::kStatusDone && dirty != NULL) {
-        env->CallVoidMethod(dirty, gRectClassInfo.set,
-                int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
-    }
-    return status;
-}
-
 // ----------------------------------------------------------------------------
 // Misc
 // ----------------------------------------------------------------------------
@@ -643,7 +616,6 @@
 static void android_view_GLES20Canvas_resetModifiers(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jint modifiers) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    if (modifiers & MODIFIER_SHADOW) renderer->resetShadow();
     if (modifiers & MODIFIER_SHADER) renderer->resetShader();
 }
 
@@ -655,12 +627,6 @@
 }
 
 
-static void android_view_GLES20Canvas_setupShadow(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jfloat radius, jfloat dx, jfloat dy, jint color) {
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    renderer->setupShadow(radius, dx, dy, color);
-}
-
 // ----------------------------------------------------------------------------
 // Draw filters
 // ----------------------------------------------------------------------------
@@ -1007,10 +973,6 @@
     { "nGetStencilSize",    "()I",             (void*) android_view_GLES20Canvas_getStencilSize },
 
     { "nCallDrawGLFunction", "(JJ)I",          (void*) android_view_GLES20Canvas_callDrawGLFunction },
-    { "nDetachFunctor",      "(JJ)V",          (void*) android_view_GLES20Canvas_detachFunctor },
-    { "nAttachFunctor",      "(JJ)V",          (void*) android_view_GLES20Canvas_attachFunctor },
-    { "nInvokeFunctors",     "(JLandroid/graphics/Rect;)I",
-            (void*) android_view_GLES20Canvas_invokeFunctors },
 
     { "nSave",              "(JI)I",           (void*) android_view_GLES20Canvas_save },
     { "nRestore",           "(J)V",            (void*) android_view_GLES20Canvas_restore },
@@ -1062,7 +1024,6 @@
 
     { "nResetModifiers",    "(JI)V",           (void*) android_view_GLES20Canvas_resetModifiers },
     { "nSetupShader",       "(JJ)V",           (void*) android_view_GLES20Canvas_setupShader },
-    { "nSetupShadow",       "(JFFFI)V",        (void*) android_view_GLES20Canvas_setupShadow },
 
     { "nSetupPaintFilter",  "(JII)V",          (void*) android_view_GLES20Canvas_setupPaintFilter },
     { "nResetPaintFilter",  "(J)V",            (void*) android_view_GLES20Canvas_resetPaintFilter },
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index 2e8dccf..8a426ac 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -74,15 +74,10 @@
 } gRectClassInfo;
 
 static struct {
-    jfieldID mFinalizer;
-    jfieldID mNativeCanvas;
     jfieldID mSurfaceFormat;
+    jmethodID safeCanvasSwap;
 } gCanvasClassInfo;
 
-static struct {
-    jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
 #define GET_INT(object, field) \
     env->GetIntField(object, field)
 
@@ -146,15 +141,6 @@
 // Canvas management
 // ----------------------------------------------------------------------------
 
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
-    jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
-    SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
-            GET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas));
-    SET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas, (long) newCanvas);
-    SET_LONG(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (long) newCanvas);
-    SkSafeUnref(previousCanvas);
-}
-
 static inline SkBitmap::Config convertPixelFormat(int32_t format) {
     switch (format) {
         case PIXEL_FORMAT_RGBA_8888:
@@ -213,7 +199,7 @@
     SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer->getPixelFormat());
 
     SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
-    swapCanvasPtr(env, canvas, nativeCanvas);
+    INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     SkRect clipRect;
     clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
@@ -233,7 +219,7 @@
     GraphicBufferWrapper* wrapper =
                 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
     SkCanvas* nativeCanvas = SkNEW(SkCanvas);
-    swapCanvasPtr(env, canvas, nativeCanvas);
+    INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     if (wrapper) {
         status_t status = wrapper->buffer->unlock();
@@ -332,13 +318,8 @@
     GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
 
     FIND_CLASS(clazz, "android/graphics/Canvas");
-    GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
-            "Landroid/graphics/Canvas$CanvasFinalizer;");
-    GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
     GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
-
-    FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
-    GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
+    GET_METHOD_ID(gCanvasClassInfo.safeCanvasSwap, clazz, "safeCanvasSwap", "(JZ)V");
 
     return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index 3be013b..4787d28 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -101,7 +101,6 @@
     RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
 
     BaseAnimator* animator = new RenderPropertyAnimator(property, deltaType, deltaValue);
-    animator->incStrong(0);
     animator->setListener(new AnimationListenerBridge(env, weakThis));
     return reinterpret_cast<jlong>( animator );
 }
@@ -111,7 +110,6 @@
     RenderPropertyAnimator::DeltaValueType deltaType = toDeltaType(deltaTypeRaw);
     CanvasPropertyPrimitive* canvasProperty = reinterpret_cast<CanvasPropertyPrimitive*>(canvasPropertyPtr);
     BaseAnimator* animator = new CanvasPropertyPrimitiveAnimator(canvasProperty, deltaType, deltaValue);
-    animator->incStrong(0);
     animator->setListener(new AnimationListenerBridge(env, weakThis));
     return reinterpret_cast<jlong>( animator );
 }
@@ -124,7 +122,6 @@
     CanvasPropertyPaintAnimator::PaintField paintField = toPaintField(paintFieldRaw);
     BaseAnimator* animator = new CanvasPropertyPaintAnimator(
             canvasProperty, paintField, deltaType, deltaValue);
-    animator->incStrong(0);
     animator->setListener(new AnimationListenerBridge(env, weakThis));
     return reinterpret_cast<jlong>( animator );
 }
@@ -135,11 +132,6 @@
     animator->setDuration(duration);
 }
 
-static void unref(JNIEnv* env, jobject clazz, jlong objPtr) {
-    VirtualLightRefBase* obj = reinterpret_cast<VirtualLightRefBase*>(objPtr);
-    obj->decStrong(0);
-}
-
 #endif
 
 // ----------------------------------------------------------------------------
@@ -154,7 +146,6 @@
     { "nCreateCanvasPropertyFloatAnimator", "(Ljava/lang/ref/WeakReference;JIF)J", (void*) createCanvasPropertyFloatAnimator },
     { "nCreateCanvasPropertyPaintAnimator", "(Ljava/lang/ref/WeakReference;JIIF)J", (void*) createCanvasPropertyPaintAnimator },
     { "nSetDuration", "(JI)V", (void*) setDuration },
-    { "nUnref", "(J)V", (void*) unref },
 #endif
 };
 
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index ab6c1e0..6c9d060 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -69,15 +69,10 @@
 } gRectClassInfo;
 
 static struct {
-    jfieldID mFinalizer;
-    jfieldID mNativeCanvas;
     jfieldID mSurfaceFormat;
+    jmethodID safeCanvasSwap;
 } gCanvasClassInfo;
 
-static struct {
-    jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
 // ----------------------------------------------------------------------------
 
 // this is just a pointer we use to pass to inc/decStrong
@@ -191,15 +186,6 @@
     }
 }
 
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
-  jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
-  SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
-          env->GetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas));
-  env->SetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas, (jlong)newCanvas);
-  env->SetLongField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (jlong)newCanvas);
-  SkSafeUnref(previousCanvas);
-}
-
 static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
         jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
     sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
@@ -247,7 +233,7 @@
     }
 
     SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
-    swapCanvasPtr(env, canvasObj, nativeCanvas);
+    env->CallVoidMethod(canvasObj, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     if (dirtyRectPtr) {
         nativeCanvas->clipRect( SkRect::Make(reinterpret_cast<const SkIRect&>(dirtyRect)) );
@@ -277,7 +263,7 @@
 
     // detach the canvas from the surface
     SkCanvas* nativeCanvas = SkNEW(SkCanvas);
-    swapCanvasPtr(env, canvasObj, nativeCanvas);
+    env->CallVoidMethod(canvasObj, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     // unlock surface
     status_t err = surface->unlockAndPost();
@@ -388,12 +374,8 @@
     gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "(J)V");
 
     clazz = env->FindClass("android/graphics/Canvas");
-    gCanvasClassInfo.mFinalizer = env->GetFieldID(clazz, "mFinalizer", "Landroid/graphics/Canvas$CanvasFinalizer;");
-    gCanvasClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "J");
     gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I");
-
-    clazz = env->FindClass("android/graphics/Canvas$CanvasFinalizer");
-    gCanvasFinalizerClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "J");
+    gCanvasClassInfo.safeCanvasSwap = env->GetMethodID(clazz, "safeCanvasSwap", "(JZ)V");
 
     clazz = env->FindClass("android/graphics/Rect");
     gRectClassInfo.left = env->GetFieldID(clazz, "left", "I");
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 77ede33..9258543 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -44,16 +44,11 @@
 } gRectClassInfo;
 
 static struct {
-    jfieldID mFinalizer;
-    jfieldID mNativeCanvas;
     jfieldID mSurfaceFormat;
+    jmethodID safeCanvasSwap;
 } gCanvasClassInfo;
 
 static struct {
-    jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
-static struct {
     jfieldID nativeWindow;
 } gTextureViewClassInfo;
 
@@ -125,15 +120,6 @@
     }
 }
 
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
-    jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
-    SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
-          env->GetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas));
-    env->SetLongField(canvasObj, gCanvasClassInfo.mNativeCanvas, (jlong)newCanvas);
-    env->SetLongField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (jlong)newCanvas);
-    SkSafeUnref(previousCanvas);
-}
-
 static jboolean android_view_TextureView_lockCanvas(JNIEnv* env, jobject,
         jlong nativeWindow, jobject canvas, jobject dirtyRect) {
 
@@ -175,7 +161,7 @@
     SET_INT(canvas, gCanvasClassInfo.mSurfaceFormat, buffer.format);
 
     SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
-    swapCanvasPtr(env, canvas, nativeCanvas);
+    INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     SkRect clipRect;
     clipRect.set(rect.left, rect.top, rect.right, rect.bottom);
@@ -193,7 +179,7 @@
         jlong nativeWindow, jobject canvas) {
 
     SkCanvas* nativeCanvas = SkNEW(SkCanvas);
-    swapCanvasPtr(env, canvas, nativeCanvas);
+    INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     if (nativeWindow) {
         sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
@@ -241,13 +227,8 @@
     GET_FIELD_ID(gRectClassInfo.bottom, clazz, "bottom", "I");
 
     FIND_CLASS(clazz, "android/graphics/Canvas");
-    GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
-            "Landroid/graphics/Canvas$CanvasFinalizer;");
-    GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
     GET_FIELD_ID(gCanvasClassInfo.mSurfaceFormat, clazz, "mSurfaceFormat", "I");
-
-    FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
-    GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
+    GET_METHOD_ID(gCanvasClassInfo.safeCanvasSwap, clazz, "safeCanvasSwap", "(JZ)V");
 
     FIND_CLASS(clazz, "android/view/TextureView");
     GET_FIELD_ID(gTextureViewClassInfo.nativeWindow, clazz, "mNativeWindow", "J");
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 6ff28e3..cdd036e 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -197,6 +197,12 @@
     proxy->setup(width, height);
 }
 
+static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jboolean opaque) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    proxy->setOpaque(opaque);
+}
+
 static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jlong frameTimeNanos, jint dirtyLeft, jint dirtyTop,
         jint dirtyRight, jint dirtyBottom) {
@@ -279,6 +285,7 @@
     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
     { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
     { "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup },
+    { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
     { "nSyncAndDrawFrame", "(JJIIII)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
     { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
     { "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
diff --git a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
new file mode 100644
index 0000000..ce6f207
--- /dev/null
+++ b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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 <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+namespace android {
+
+static void incStrong(JNIEnv* env, jobject clazz, jlong objPtr) {
+    VirtualLightRefBase* obj = reinterpret_cast<VirtualLightRefBase*>(objPtr);
+    obj->incStrong(0);
+}
+
+static void decStrong(JNIEnv* env, jobject clazz, jlong objPtr) {
+    VirtualLightRefBase* obj = reinterpret_cast<VirtualLightRefBase*>(objPtr);
+    obj->decStrong(0);
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "com/android/internal/util/VirtualRefBasePtr";
+
+static JNINativeMethod gMethods[] = {
+    { "nIncStrong", "(J)V", (void*) incStrong },
+    { "nDecStrong", "(J)V", (void*) decStrong },
+};
+
+int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv* env) {
+    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+
+} // namespace android
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 241500a..cdb77f1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1295,10 +1295,9 @@
     <!-- @hide Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
          that removes restrictions on where broadcasts can be sent and allows other
          types of interactions. -->
-    <!-- TODO: Remove the system protection level.-->
     <permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature|system"
+        android:protectionLevel="signature"
         android:label="@string/permlab_interactAcrossUsersFull"
         android:description="@string/permdesc_interactAcrossUsersFull" />
 
diff --git a/core/res/res/anim/button_state_list_anim_quantum.xml b/core/res/res/anim/button_state_list_anim_quantum.xml
new file mode 100644
index 0000000..01989a4
--- /dev/null
+++ b/core/res/res/anim/button_state_list_anim_quantum.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true" android:state_enabled="true">
+        <set>
+            <objectAnimator android:propertyName="translationZ"
+                            android:duration="@integer/button_pressed_animation_duration"
+                            android:valueTo="@dimen/button_pressed_z"
+                            android:valueType="floatType"/>
+        </set>
+    </item>
+    <!-- base state -->
+    <item>
+        <set>
+            <objectAnimator android:propertyName="translationZ"
+                            android:duration="@integer/button_pressed_animation_duration"
+                            android:valueTo="0"
+                            android:valueType="floatType"/>
+        </set>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..1880a15
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..aecb4d2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..8401f91
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..5832865
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..6d14962
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..aee057c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..fb5801e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..fdb5271
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..b8c7397
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..d0395a8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..59bb437
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..c053b90
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..eb30a79
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..1af0bff
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..3b36e7d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..c12d20a
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_check_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..882365b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..f6c7094
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..0e326c9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..8bf1170
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..cedb66e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..257d7ba
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..e07b36e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..ef94200
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..ad67004
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..50796e2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..ba7be9e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..bdbfe78
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..fe89951
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..840c88f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..621d1d2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..fd8be89
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_radio_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb_am.png b/core/res/res/drawable-hdpi/stat_sys_adb_am.png
deleted file mode 100644
index dad614c..0000000
--- a/core/res/res/drawable-hdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-ldpi/stat_sys_adb_am.png b/core/res/res/drawable-ldpi/stat_sys_adb_am.png
deleted file mode 100644
index 0171adb..0000000
--- a/core/res/res/drawable-ldpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..0f44ff9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..9d5dda0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..e4ce802
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..d1806ac
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..ab9315b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..46e90e6
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..e8c56ff
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..59dcb7e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..e9bd4a2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..1d05037
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..91b40de
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..c531cab
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..11bb387
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..8843210
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..6ff2f3d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..a03c1e2
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_check_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..0a22e1a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..2e2469c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..c1054d9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..cf8d80a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..9d9e870
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..1bad701
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..a84a54f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..4d8050b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..374172c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..233036e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..61d9b58
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..274e983
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..acf16e5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..ee48241
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..dbbb736
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..bcabd0d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_radio_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb_am.png b/core/res/res/drawable-mdpi/stat_sys_adb_am.png
deleted file mode 100644
index 5482f34..0000000
--- a/core/res/res/drawable-mdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
deleted file mode 100644
index 6351c2d..0000000
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
new file mode 100644
index 0000000..8eb00fa
--- /dev/null
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size android:width="400dp" android:height="400dp"/>
+
+    <viewport android:viewportHeight="25" android:viewportWidth="25" />
+
+    <group>
+        <path
+            android:name="shadow"
+            android:pathData="m12,2.5 a11,11 0 1,0 1,0
+            M6.5,7.5
+            l5,0 l0,7 l7,0 l0,5 l-12,0 z"
+            android:fill="#40000000"
+            />
+        <path
+            android:name="circle-L-ranch"
+            android:pathData="m12,1.5 a11,11 0 1,0 1,0
+            M6.5,6.5
+            l5,0 l0,7 l7,0 l0,5 l-12,0 z"
+            android:fill="#FFFFFF40"
+            />
+    </group>
+</vector>
+
+
diff --git a/core/res/res/drawable-nodpi/stat_sys_adb.xml b/core/res/res/drawable-nodpi/stat_sys_adb.xml
new file mode 100644
index 0000000..49028b4
--- /dev/null
+++ b/core/res/res/drawable-nodpi/stat_sys_adb.xml
@@ -0,0 +1,30 @@
+<!--
+    Copyright (C) 2014 The Android Open Source Project
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at"+
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" >
+    <size android:width="25dp" android:height="25dp"/>
+
+    <viewport android:viewportHeight="25" android:viewportWidth="25" />
+
+    <group>
+        <path
+            android:name="adb"
+            android:pathData="m3,3l8,0l0,11l11,0l0,8l-19,0z"
+            android:fill="#FFFFFFFF"
+            />
+    </group>
+</vector>
+
+
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..25500e8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..b136e25
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..6a94e30
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..d386421
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..c811385
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..58b3267
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..0659e72
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..b4227d1
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..714ef00
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..139595b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..4491107
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..20eb752
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..532c9f2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..0d78a32
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..af29678
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..23eb9e3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_check_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..cd11e14
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..b10db83
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..efeb6fb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..83080af
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..b9cc322
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..3b5f9c4
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..58c93db
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..0f1d010
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..05a7a0f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..9345035
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..5f149b7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..191f369
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..44e08e6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..5a9dfa0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..ee921c6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..567bb0c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/btn_radio_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
deleted file mode 100644
index e53f498..0000000
--- a/core/res/res/drawable-xhdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..1881f54
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..6f8ec2d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..c954ed9
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..9d1a47e
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..ce63631
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..430c134
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..cdebf83
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..40ceadb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..fb13eb2
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..d716fba
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..b8be041
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..bad0c3c
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..a6368fb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..234e5d1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..3e7796d
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..0673999
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_check_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00000_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00000_qntm_alpha.png
new file mode 100644
index 0000000..4779944
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00000_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00001_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00001_qntm_alpha.png
new file mode 100644
index 0000000..866f7b7
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00001_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00002_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00002_qntm_alpha.png
new file mode 100644
index 0000000..76aae57
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00002_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00003_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00003_qntm_alpha.png
new file mode 100644
index 0000000..0cd470a1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00003_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00004_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00004_qntm_alpha.png
new file mode 100644
index 0000000..0015b39
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00004_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00005_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00005_qntm_alpha.png
new file mode 100644
index 0000000..2f69f5b
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00005_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00006_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00006_qntm_alpha.png
new file mode 100644
index 0000000..77142fd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00006_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00007_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00007_qntm_alpha.png
new file mode 100644
index 0000000..2f81277
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00007_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00008_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00008_qntm_alpha.png
new file mode 100644
index 0000000..d37fe60
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00008_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00009_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00009_qntm_alpha.png
new file mode 100644
index 0000000..cb62079
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00009_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00010_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00010_qntm_alpha.png
new file mode 100644
index 0000000..82dc428
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00010_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00011_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00011_qntm_alpha.png
new file mode 100644
index 0000000..2cba2fb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00011_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00012_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00012_qntm_alpha.png
new file mode 100644
index 0000000..5de1952
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00012_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00013_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00013_qntm_alpha.png
new file mode 100644
index 0000000..1c22a17
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00013_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00014_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00014_qntm_alpha.png
new file mode 100644
index 0000000..7f652fc
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00014_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_radio_anim_00015_qntm_alpha.png b/core/res/res/drawable-xxhdpi/btn_radio_anim_00015_qntm_alpha.png
new file mode 100644
index 0000000..076acbd
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/btn_radio_anim_00015_qntm_alpha.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png b/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
deleted file mode 100644
index d6018dd..0000000
--- a/core/res/res/drawable-xxhdpi/stat_sys_adb_am.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/btn_check_quantum_anim.xml b/core/res/res/drawable/btn_check_quantum_anim.xml
index 0600522..96715a4 100644
--- a/core/res/res/drawable/btn_check_quantum_anim.xml
+++ b/core/res/res/drawable/btn_check_quantum_anim.xml
@@ -1,3 +1,4 @@
+<?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");
@@ -13,67 +14,92 @@
      limitations under the License.
 -->
 
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:trigger="state_checked"
-    android:versionCode="1" >
+<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false" android:state_checked="true">
+        <bitmap android:src="@drawable/btn_check_anim_00015_qntm_alpha"
+            android:tint="?attr/colorControlActivated"
+            android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:state_enabled="false">
+        <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha"
+            android:tint="?attr/colorControlNormal"
+            android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:state_checked="true" android:id="@+id/on">
+        <bitmap android:src="@drawable/btn_check_anim_00015_qntm_alpha"
+            android:tint="?attr/colorControlActivated" />
+    </item>
+    <item android:id="@+id/off">
+        <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+    <transition android:fromId="@+id/off" android:toId="@+id/on" android:reversible="true">
+        <animation-list>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00000_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00001_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00002_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00003_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00004_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00005_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00006_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00007_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00008_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00009_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00010_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00011_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00012_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00013_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00014_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_check_anim_00015_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+        </animation-list>
+    </transition>
+</animated-selector>
 
-    <size
-        android:height="32dp"
-        android:width="32dp" />
-
-    <viewport
-        android:viewportHeight="320"
-        android:viewportWidth="320" />
-
-    <group>
-        <path
-            android:name="box1"
-            android:pathData="M 240,80 L 240,240 L 80,240 L 80,80 L 240,80 L 240,80 z"
-            android:stroke="?attr/colorControlNormal"
-            android:strokeWidth="20"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
-    <group>
-        <path
-            android:name="box2"
-            android:pathData="M 160,200 L 160,240 L 120,240 L 120,200 L 160,200 L 160,200 z"
-            android:stroke="?attr/colorControlNormal"
-            android:strokeWidth="10"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
-    <group>
-        <path
-            android:name="box3"
-            android:pathData="M 160,216.5 L 143.5,240 L 120,223.5 L 136.5,200 L 160,216.5 L 160,216.5 z"
-            android:rotation="35"
-            android:pivotX="140"
-            android:pivotY="220"
-            android:fill="?attr/colorControlNormal"
-            android:stroke="?attr/colorControlNormal"
-            android:strokeWidth="5"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
-    <group>
-        <path
-            android:name="box4"
-            android:pathData="M 160,216.5 L 143.5,240 L 120,223.5 L 136.5,200 L 160,216.5 L 160,216.5 z"
-            android:fill="?attr/colorControlActivated"
-            android:stroke="?attr/colorControlActivated"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
-    <group>
-        <path
-            android:name="check"
-            android:pathData="M 232.1,80.6 L 248.5,92.1 L 145.2,239.5 L 71.5,187.8 L 83,171.5 L 140.3,211.7 z"
-            android:fill="?attr/colorControlActivated" />
-    </group>
-
-    <animation
-        android:durations="300,100,0,300"
-        android:sequence="box1,box2,box3,box4,check" />
-
-</vector>
diff --git a/core/res/res/drawable/btn_radio_quantum_anim.xml b/core/res/res/drawable/btn_radio_quantum_anim.xml
new file mode 100644
index 0000000..5068b7a
--- /dev/null
+++ b/core/res/res/drawable/btn_radio_quantum_anim.xml
@@ -0,0 +1,104 @@
+<?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.
+-->
+
+<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false" android:state_checked="true">
+        <bitmap android:src="@drawable/btn_radio_anim_00015_qntm_alpha"
+            android:tint="?attr/colorControlActivated"
+            android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:state_enabled="false">
+        <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha"
+            android:tint="?attr/colorControlNormal"
+            android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:state_checked="true" android:id="@+id/on">
+        <bitmap android:src="@drawable/btn_radio_anim_00015_qntm_alpha"
+            android:tint="?attr/colorControlActivated" />
+    </item>
+    <item android:id="@+id/off">
+        <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+    <transition android:fromId="@+id/off" android:toId="@+id/on" android:reversible="true">
+        <animation-list>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00000_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00001_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00002_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00003_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00004_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00005_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00006_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00007_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00008_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00009_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00010_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00011_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00012_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00013_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00014_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+            <item android:duration="33">
+                <bitmap android:src="@drawable/btn_radio_anim_00015_qntm_alpha"
+                    android:tint="?attr/colorControlActivated" />
+            </item>
+        </animation-list>
+    </transition>
+</animated-selector>
diff --git a/core/res/res/drawable/notification_icon_legacy_bg.xml b/core/res/res/drawable/notification_icon_legacy_bg.xml
index 4ac67c3..cc5755d 100644
--- a/core/res/res/drawable/notification_icon_legacy_bg.xml
+++ b/core/res/res/drawable/notification_icon_legacy_bg.xml
@@ -18,5 +18,5 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="oval">
     <solid
-            android:color="@color/notification_icon_legacy_bg_color"/>
+            android:color="@color/notification_icon_bg_color"/>
 </shape>
diff --git a/core/res/res/layout/alert_dialog_micro.xml b/core/res/res/layout/alert_dialog_micro.xml
index f8eb46c..abdbd16 100644
--- a/core/res/res/layout/alert_dialog_micro.xml
+++ b/core/res/res/layout/alert_dialog_micro.xml
@@ -20,6 +20,8 @@
     android:id="@+id/parentPanel"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:background="@android:color/white"
+    android:layout_gravity="center"
     android:orientation="vertical">
 
     <LinearLayout android:id="@+id/topPanel"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 4358dd3..790567e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -31,11 +31,11 @@
     <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dag <xliff:g id="HOURS">%2$d</xliff:g> uur"</string>
     <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dag <xliff:g id="HOURS">%2$d</xliff:g> uur"</string>
     <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> uur"</string>
-    <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> uur <xliff:g id="MINUTES">%2$d</xliff:g> minute"</string>
-    <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> uur <xliff:g id="MINUTES">%2$d</xliff:g> minuut"</string>
+    <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> u. <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
+    <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> u. <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
     <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> minute"</string>
-    <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> minuut <xliff:g id="SECONDS">%2$d</xliff:g> sekondes"</string>
-    <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> minuut <xliff:g id="SECONDS">%2$d</xliff:g> sekond"</string>
+    <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> s."</string>
+    <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> s."</string>
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sekondes"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sekonde"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Titelloos&gt;"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index dbc0d43..66b4a90 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -741,7 +741,7 @@
     <string name="policylab_expirePassword" msgid="885279151847254056">"تنظیم زمان انقضای رمز ورود قفل صفحه"</string>
     <string name="policydesc_expirePassword" msgid="1729725226314691591">"کنترل کنید چند وقت یک بار باید گذرواژه صفحه قفل عوض شود."</string>
     <string name="policylab_encryptedStorage" msgid="8901326199909132915">"تنظیم رمزگذاری حافظه"</string>
-    <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"باید اطلاعات ذخیره شده برنامه رمزگذاری شود."</string>
+    <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"اطلاعات ذخیره شده برنامه باید رمزگذاری شود."</string>
     <string name="policylab_disableCamera" msgid="6395301023152297826">"غیر فعال کردن دوربین ها"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"جلوگیری از استفاده از همه دوربین‌های دستگاه."</string>
     <string name="policylab_disableKeyguardFeatures" msgid="266329104542638802">"غیرفعال کردن ویژگی‌‌ها در محافظ کلید"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 03dfb12..eb2540d 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -188,10 +188,8 @@
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string>
-    <!-- no translation found for user_owner_label (2804351898001038951) -->
-    <skip />
-    <!-- no translation found for managed_profile_label (6260850669674791528) -->
-    <skip />
+    <string name="user_owner_label" msgid="2804351898001038951">"Henkilökohtainen"</string>
+    <string name="managed_profile_label" msgid="6260850669674791528">"Työ"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Maksulliset palvelut"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Suorita mahdollisesti maksullisia toimintoja."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Omat viestit"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index ea9ffb3..751327b 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -188,10 +188,8 @@
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
-    <!-- no translation found for user_owner_label (2804351898001038951) -->
-    <skip />
-    <!-- no translation found for managed_profile_label (6260850669674791528) -->
-    <skip />
+    <string name="user_owner_label" msgid="2804351898001038951">"Peribadi"</string>
+    <string name="managed_profile_label" msgid="6260850669674791528">"Tempat Kerja"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Perkhidmatan yang anda perlu bayar"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Melakukan perkara yang boleh mengenakan bayaran kepada anda."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Mesej anda"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index ecec099..f9b9fd2 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -31,13 +31,13 @@
     <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dia <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
     <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dia <xliff:g id="HOURS">%2$d</xliff:g> h"</string>
     <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> horas"</string>
-    <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
-    <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min."</string>
-    <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min."</string>
-    <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> seg."</string>
-    <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min. <xliff:g id="SECONDS">%2$d</xliff:g> seg."</string>
-    <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> seg."</string>
-    <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> seg."</string>
+    <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
+    <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> h <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
+    <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
+    <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> seg"</string>
+    <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> seg"</string>
+    <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> seg"</string>
+    <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> seg"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Sem nome&gt;"</string>
     <string name="ellipsis" msgid="7899829516048813237">"…"</string>
     <string name="ellipsis_two_dots" msgid="1228078994866030736">"‥"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 93107ca..be2ed29 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -188,10 +188,8 @@
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"&gt;999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
-    <!-- no translation found for user_owner_label (2804351898001038951) -->
-    <skip />
-    <!-- no translation found for managed_profile_label (6260850669674791528) -->
-    <skip />
+    <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
+    <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Serviços que geram gastos"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Faça coisas que podem custar dinheiro."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Suas mensagens"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 568e093..33a5a81 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -188,10 +188,8 @@
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string>
-    <!-- no translation found for user_owner_label (2804351898001038951) -->
-    <skip />
-    <!-- no translation found for managed_profile_label (6260850669674791528) -->
-    <skip />
+    <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
+    <string name="managed_profile_label" msgid="6260850669674791528">"Serviciu"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servicii cu plată"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Efectuează acţiuni care sunt cu plată."</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"Mesajele dvs."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 8a0141a..c7c5a08 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -34,10 +34,10 @@
     <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> ч. <xliff:g id="MINUTES">%2$d</xliff:g> мин."</string>
     <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> ч. <xliff:g id="MINUTES">%2$d</xliff:g> мин."</string>
     <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> мин."</string>
-    <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> мин. <xliff:g id="SECONDS">%2$d</xliff:g> с."</string>
-    <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> мин. <xliff:g id="SECONDS">%2$d</xliff:g> с."</string>
-    <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> с."</string>
-    <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> с."</string>
+    <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> мин. <xliff:g id="SECONDS">%2$d</xliff:g> с"</string>
+    <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> мин. <xliff:g id="SECONDS">%2$d</xliff:g> с"</string>
+    <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> с"</string>
+    <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> с"</string>
     <string name="untitled" msgid="4638956954852782576">"&lt;Без названия&gt;"</string>
     <string name="ellipsis" msgid="7899829516048813237">"…"</string>
     <string name="ellipsis_two_dots" msgid="1228078994866030736">"..."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 793e5bf..3476692 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -188,10 +188,8 @@
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
-    <!-- no translation found for user_owner_label (2804351898001038951) -->
-    <skip />
-    <!-- no translation found for managed_profile_label (6260850669674791528) -->
-    <skip />
+    <string name="user_owner_label" msgid="2804351898001038951">"个人"</string>
+    <string name="managed_profile_label" msgid="6260850669674791528">"企业"</string>
     <string name="permgrouplab_costMoney" msgid="5429808217861460401">"需要您付费的服务"</string>
     <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"执行可能需要您付费的操作。"</string>
     <string name="permgrouplab_messages" msgid="7521249148445456662">"您的信息"</string>
@@ -716,8 +714,8 @@
     <string name="permdesc_accessNotifications" msgid="458457742683431387">"允许该应用检索、检查并清除通知,包括其他应用发布的通知。"</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"绑定到通知侦听器服务"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"允许应用绑定到通知侦听器服务的顶级接口(普通应用绝不需要此权限)。"</string>
-    <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"绑定到条件提供方服务"</string>
-    <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允许应用绑定到条件提供方服务的顶级接口。普通应用绝不需要此权限。"</string>
+    <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"绑定到条件提供程序服务"</string>
+    <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"允许应用绑定到条件提供程序服务的顶级接口。普通应用绝不需要此权限。"</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"调用运营商提供的配置应用"</string>
     <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允许应用调用运营商提供的配置应用。普通应用绝不需要此权限。"</string>
     <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"监听网络状况的观测信息"</string>
@@ -1388,7 +1386,7 @@
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"壁纸"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"更改壁纸"</string>
     <string name="notification_listener_binding_label" msgid="2014162835481906429">"通知侦听器"</string>
-    <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"条件提供方"</string>
+    <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"条件提供程序"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN 已激活"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"“<xliff:g id="APP">%s</xliff:g>”已激活 VPN"</string>
     <string name="vpn_text" msgid="3011306607126450322">"触摸可管理网络。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 547ca27..4a67538 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1169,7 +1169,7 @@
     <string name="whichHomeApplication" msgid="4616420172727326782">"選取主螢幕應用程式"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"設為預設應用程式。"</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"前往 [系統設定] &gt; [應用程式] &gt; [下載] 清除預設值。"</string>
-    <string name="chooseActivity" msgid="7486876147751803333">"選擇一種動作"</string>
+    <string name="chooseActivity" msgid="7486876147751803333">"選擇分享方式"</string>
     <string name="chooseUsbActivity" msgid="6894748416073583509">"選取要以 USB 裝置存取的應用程式"</string>
     <string name="noApplications" msgid="2991814273936504689">"沒有應用程式可執行這項操作。"</string>
     <string name="aerr_title" msgid="1905800560317137752"></string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0326e18..28e75e6 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2364,6 +2364,9 @@
         <!-- Specifies that this view should permit nested scrolling within a compatible
              ancestor view. -->
         <attr name="nestedScrollingEnabled" format="boolean" />
+
+        <!-- Sets the state-based animator for the View. -->
+        <attr name="stateListAnimator" format="reference"/>
     </declare-styleable>
 
     <!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -4236,6 +4239,58 @@
         <attr name="autoMirrored"/>
     </declare-styleable>
 
+    <!-- Drawable used to render several states with animated transitions. Each state
+         is represented by a child drawable with an optional keyframe ID. -->
+    <declare-styleable name="AnimatedStateListDrawable">
+        <!-- Indicates whether the drawable should be initially visible. -->
+        <attr name="visible" />
+        <!-- If true, allows the drawable's padding to change based on the
+             current state that is selected.  If false, the padding will
+             stay the same (based on the maximum padding of all the states).
+             Enabling this feature requires that the owner of the drawable
+             deal with performing layout when the state changes, which is
+             often not supported. -->
+        <attr name="variablePadding" />
+        <!-- If true, the drawable's reported internal size will remain
+             constant as the state changes; the size is the maximum of all
+             of the states.  If false, the size will vary based on the
+             current state. -->
+        <attr name="constantSize" />
+        <!-- Enables or disables dithering of the bitmap if the bitmap does not have the
+             same pixel configuration as the screen (for instance: a ARGB 8888 bitmap with
+             an RGB 565 screen). -->
+        <attr name="dither" />
+        <!-- Amount of time (in milliseconds) to fade in a new state drawable. -->
+        <attr name="enterFadeDuration" />
+        <!-- Amount of time (in milliseconds) to fade out an old state drawable. -->
+        <attr name="exitFadeDuration" />
+        <!-- Indicates if the drawable needs to be mirrored when its layout direction is
+             RTL (right-to-left). -->
+        <attr name="autoMirrored"/>
+    </declare-styleable>
+
+    <!-- Transition used to animate between states with keyframe IDs. -->
+    <declare-styleable name="AnimatedStateListDrawableItem">
+        <!-- Reference to a drawable resource to use for the frame.  If not
+             given, the drawable must be defined by the first child tag. -->
+        <attr name="drawable" />
+        <!-- Keyframe identifier for use in specifying transitions. -->
+        <attr name="id" />
+    </declare-styleable>
+
+    <!-- Transition used to animate between states with keyframe IDs. -->
+    <declare-styleable name="AnimatedStateListDrawableTransition">
+        <!-- Keyframe identifier for the starting state. -->
+        <attr name="fromId" format="reference" />
+        <!-- Keyframe identifier for the ending state. -->
+        <attr name="toId" format="reference" />
+        <!-- Reference to a animation drawable resource to use for the frame.  If not
+             given, the animation drawable must be defined by the first child tag. -->
+        <attr name="drawable" />
+        <!-- Whether this transition is reversible. -->
+        <attr name="reversible" format="boolean" />
+    </declare-styleable>
+
     <!-- Drawable used to render several animated frames. -->
     <declare-styleable name="AnimationDrawable">
         <attr name="visible" />
@@ -4255,6 +4310,11 @@
         <attr name="drawable" format="reference" />
     </declare-styleable>
 
+    <!-- Attributes that can be assigned to a StateListAnimator item. -->
+    <declare-styleable name="StateListAnimatorItem">
+        <attr name="animation"/>
+    </declare-styleable>
+
     <!-- Drawable used to render a geometric shape, with a gradient or a solid color. -->
     <declare-styleable name="GradientDrawable">
         <!-- Indicates whether the drawable should intially be visible. -->
@@ -4652,18 +4712,6 @@
 
     <!-- Drawable used to draw Vector Drawables. -->
     <declare-styleable name="VectorDrawable">
-           <!-- What event triggers the animation -->
-        <attr name="trigger" format="enum">
-            <enum name="state_pressed" value="1" />
-            <enum name="state_focused" value="2" />
-            <enum name="state_hovered" value="3" />
-            <enum name="state_selected" value="4" />
-            <enum name="state_checkable" value="5" />
-            <enum name="state_checked" value="6" />
-            <enum name="state_enabled" value="7" />
-            <enum name="state_activated" value="8" />
-            <enum name="state_window_focused" value="9" />
-        </attr>
         <attr name="versionCode" />
     </declare-styleable>
 
@@ -4683,42 +4731,6 @@
         <attr name="height" />
     </declare-styleable>
 
-    <!-- Define the animations of drawable -->
-    <declare-styleable name="VectorDrawableAnimation">
-        <!-- Configures this animation sequence between the named paths  -->
-        <attr name="sequence" format="string"/>
-        <!-- Limits an animation to only interpolate the selected variable  -->
-        <attr name="limitTo" format="enum">
-            <enum name="unlimited" value="0"/>
-            <enum name="path" value="1"/>
-            <enum name="rotation" value="2"/>
-            <enum name="trimPathStart" value="3"/>
-            <enum name="trimPathEnd" value="4"/>
-            <enum name="trimPathOffset" value="5"/>
-        </attr>
-        <!-- Number of times to loop this aspect of the animation -->
-        <attr name="repeatCount"/>
-        <!-- A list of times in milliseconds to transision from on path to another.
-         List must contain one less than the number of named paths
-         e.g. given sequence="A,B,C,D" durations="100,0,100" implies 100ms for the
-         "A" to "B" transision instantanious switch to "C" and 100ms for "C" to "D". -->
-        <attr name="durations" format="string" />
-        <!-- The delay before stating this aspect of the animation in milli seconds -->
-        <attr name="startDelay" />
-        <!-- when repeating how does it repeat back and forth or a to b -->
-        <attr name="repeatStyle" format="enum">
-            <enum name="forward"  value="0"/>
-            <enum name="reverse"  value="1"/>[]
-        </attr>
-        <!-- how does the animation progress from start to finish -->
-        <attr name="animate" format="enum">
-            <enum name="linear"  value="0"/>
-            <enum name="easeIn"  value="1"/>
-            <enum name="easeOut"  value="2"/>
-            <enum name="easeInOut"  value="3"/>
-        </attr>
-    </declare-styleable>
-
     <!-- Defines the path used in Vector Drawables. -->
     <declare-styleable name="VectorDrawablePath">
         <!-- The Name of this path -->
@@ -4763,26 +4775,6 @@
         </attr>
         <!-- sets the Miter limit for a stroked path -->
         <attr name="strokeMiterLimit" format="float"/>
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_pressed" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_focused" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_selected" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_window_focused" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_enabled" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_activated" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_accelerated" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_hovered" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_checked" />
-        <!-- sets a condition to be met to draw path -->
-        <attr name="state_checkable" />
     </declare-styleable>
 
     <!-- ========================== -->
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 761170d..7d3fb44 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -123,7 +123,7 @@
     <drawable name="notification_template_icon_bg">#3333B5E5</drawable>
     <drawable name="notification_template_icon_low_bg">#0cffffff</drawable>
 
-    <color name="notification_icon_legacy_bg_color">#ff4285F4</color>
+    <color name="notification_icon_bg_color">#ffa3a3a3</color>
     <color name="notification_action_legacy_color_filter">#ff555555</color>
 
     <!-- Keyguard colors -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 6b2c788..bf92f9b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -143,6 +143,8 @@
     <!-- Preferred width of the search view. -->
     <dimen name="search_view_preferred_width">320dip</dimen>
 
+    <!-- Dialog padding for round display -->
+    <dimen name="alert_dialog_round_padding">27dip</dimen>
     <!-- Dialog title height -->
     <dimen name="alert_dialog_title_height">64dip</dimen>
     <!-- Dialog button bar height -->
diff --git a/core/res/res/values/dimens_quantum.xml b/core/res/res/values/dimens_quantum.xml
index cebee12..53e97fd 100644
--- a/core/res/res/values/dimens_quantum.xml
+++ b/core/res/res/values/dimens_quantum.xml
@@ -49,4 +49,7 @@
 
     <dimen name="floating_window_z">16dp</dimen>
     <dimen name="floating_window_margin">32dp</dimen>
+
+    <!-- the amount of elevation for pressed button state-->
+    <dimen name="button_pressed_z">2dp</dimen>
 </resources>
diff --git a/core/res/res/values/integers.xml b/core/res/res/values/integers.xml
index dc90bbf..e6748c4 100644
--- a/core/res/res/values/integers.xml
+++ b/core/res/res/values/integers.xml
@@ -19,4 +19,5 @@
 <resources>
     <integer name="kg_carousel_angle">75</integer>
     <integer name="kg_glowpad_rotation_offset">0</integer>
+    <integer name="button_pressed_animation_duration">100</integer>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 8874c30..ecb22ae 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2116,7 +2116,6 @@
   <public type="attr" name="controlY2" />
   <public type="attr" name="sharedElementName" />
   <public type="attr" name="transitionGroup" />
-  <public type="attr" name="trigger" />
   <public type="attr" name="viewportWidth" />
   <public type="attr" name="viewportHeight" />
   <public type="attr" name="fillOpacity" />
@@ -2125,17 +2124,12 @@
   <public type="attr" name="stroke" />
   <public type="attr" name="strokeOpacity" />
   <public type="attr" name="strokeWidth" />
-  <public type="attr" name="durations" />
-  <public type="attr" name="sequence" />
-  <public type="attr" name="repeatStyle" />
   <public type="attr" name="trimPathStart" />
   <public type="attr" name="trimPathEnd" />
   <public type="attr" name="trimPathOffset" />
   <public type="attr" name="strokeLineCap" />
   <public type="attr" name="strokeLineJoin" />
   <public type="attr" name="clipToPath" />
-  <public type="attr" name="animate" />
-  <public type="attr" name="limitTo" />
   <public type="attr" name="requiredForProfile"/>
   <public type="attr" name="pinned" />
   <public type="attr" name="colorControlNormal" />
@@ -2171,6 +2165,10 @@
   <public type="attr" name="actionOverflowMenuStyle" />
   <public type="attr" name="documentLaunchMode" />
   <public type="attr" name="autoRemoveFromRecents" />
+  <public type="attr" name="stateListAnimator" />
+  <public type="attr" name="toId" />
+  <public type="attr" name="fromId" />
+  <public type="attr" name="reversible" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index bdaa49d..5bac1f9 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -15,6 +15,16 @@
 -->
 <resources>
     <style name="AlertDialog.Micro" parent="AlertDialog.Holo.Light">
+        <item name="fullDark">@null</item>
+        <item name="topDark">@null</item>
+        <item name="centerDark">@null</item>
+        <item name="bottomDark">@null</item>
+        <item name="fullBright">@null</item>
+        <item name="topBright">@null</item>
+        <item name="centerBright">@null</item>
+        <item name="bottomBright">@null</item>
+        <item name="bottomMedium">@null</item>
+        <item name="centerMedium">@null</item>
         <item name="layout">@layout/alert_dialog_micro</item>
     </style>
 
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index 01c3017..88a2a9f 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -364,6 +364,7 @@
         <item name="textColor">?attr/textColorPrimary</item>
         <item name="minHeight">48dip</item>
         <item name="minWidth">96dip</item>
+        <item name="stateListAnimator">@anim/button_state_list_anim_quantum</item>
     </style>
 
     <!-- Small bordered ink button -->
@@ -375,6 +376,7 @@
     <!-- Borderless ink button -->
     <style name="Widget.Quantum.Button.Borderless">
         <item name="background">@drawable/btn_borderless_quantum</item>
+        <item name="stateListAnimator">@null</item>
     </style>
 
     <!-- Small borderless ink button -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a8a4b51..5a78bfe 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -120,6 +120,7 @@
   <java-symbol type="id" name="overlay_display_window_title" />
   <java-symbol type="id" name="package_label" />
   <java-symbol type="id" name="packages_list" />
+  <java-symbol type="id" name="parentPanel" />
   <java-symbol type="id" name="pause" />
   <java-symbol type="id" name="perms_list" />
   <java-symbol type="id" name="perm_icon" />
@@ -325,6 +326,7 @@
   <java-symbol type="color" name="tab_indicator_text_v4" />
 
   <java-symbol type="dimen" name="accessibility_touch_slop" />
+  <java-symbol type="dimen" name="alert_dialog_round_padding"/>
   <java-symbol type="dimen" name="config_prefDialogWidth" />
   <java-symbol type="dimen" name="config_viewConfigurationTouchSlop" />
   <java-symbol type="dimen" name="config_viewMinFlingVelocity" />
@@ -1664,6 +1666,7 @@
   <java-symbol type="layout" name="notification_template_quantum_big_text" />
   <java-symbol type="layout" name="notification_template_quantum_inbox" />
   <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_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_micro.xml b/core/res/res/values/themes_micro.xml
index 39df700..9647947 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -47,10 +47,15 @@
         <item name="textAppearanceInverse">@style/TextAppearance.Micro</item>
     </style>
 
-    <style name="Theme.Micro.Dialog.Alert" parent="Theme.Holo.Light.Dialog.Alert">
+    <style name="Theme.Micro.Dialog.Alert">
         <item name="windowTitleStyle">@style/DialogWindowTitle.Micro</item>
         <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
         <item name="windowIsFloating">false</item>
+        <item name="windowBackground">@android:color/transparent</item>
+        <item name="windowOverscan">true</item>
+        <item name="windowContentOverlay">@null</item>
+        <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
+        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
     <style name="Theme.Micro.Dialog.AppError" parent="Theme.Micro.Dialog">
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index 39c8beb..18d6f80 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -122,7 +122,7 @@
         <item name="listDivider">@drawable/list_divider_quantum</item>
         <item name="listSeparatorTextViewStyle">@style/Widget.Quantum.TextView.ListSeparator</item>
 
-        <item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum</item>
+        <item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum_anim</item>
         <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
 
         <item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum</item>
@@ -466,7 +466,7 @@
         <item name="listDivider">@drawable/list_divider_quantum</item>
         <item name="listSeparatorTextViewStyle">@style/Widget.Quantum.Light.TextView.ListSeparator</item>
 
-        <item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum</item>
+        <item name="listChoiceIndicatorSingle">@drawable/btn_radio_quantum_anim</item>
         <item name="listChoiceIndicatorMultiple">@drawable/btn_check_quantum_anim</item>
 
         <item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum</item>
diff --git a/core/tests/coretests/res/anim/reset_state_anim.xml b/core/tests/coretests/res/anim/reset_state_anim.xml
new file mode 100644
index 0000000..918d0a3
--- /dev/null
+++ b/core/tests/coretests/res/anim/reset_state_anim.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+    <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+    <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+</set>
\ No newline at end of file
diff --git a/core/tests/coretests/res/anim/test_state_anim.xml b/core/tests/coretests/res/anim/test_state_anim.xml
new file mode 100644
index 0000000..9e08f68
--- /dev/null
+++ b/core/tests/coretests/res/anim/test_state_anim.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <set>
+            <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="10" android:valueType="floatType"/>
+            <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="20" android:valueType="floatType"/>
+            <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="20" android:valueType="floatType"/>
+        </set>
+    </item>
+    <item android:state_enabled="true" android:state_pressed="false">
+        <set>
+            <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+            <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+            <objectAnimator android:propertyName="z" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
+        </set>
+    </item>
+    <!-- base state-->
+    <item android:animation="@anim/reset_state_anim"/>
+</selector>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/animation/StateListAnimatorTest.java b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
new file mode 100644
index 0000000..38df78d
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/StateListAnimatorTest.java
@@ -0,0 +1,102 @@
+/*
+* 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.animation;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.util.StateSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.frameworks.coretests.R;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+public class StateListAnimatorTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
+
+    public StateListAnimatorTest() {
+        super(BasicAnimatorActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    public void testInflateFromAnimator() throws Exception {
+        StateListAnimator stateListAnimator = AnimatorInflater
+                .loadStateListAnimator(getActivity(), R.anim.test_state_anim);
+        assertNotNull("A state list animator should be returned", stateListAnimator);
+        assertEquals("State list animator should have three items", 3,
+                stateListAnimator.getTuples().size());
+    }
+
+    @UiThreadTest
+    public void testAttachDetach() throws Exception {
+        View view = new View(getActivity());
+        final AtomicInteger setStateCount = new AtomicInteger(0);
+        StateListAnimator stateListAnimator = new StateListAnimator() {
+            @Override
+            public void setState(int[] state) {
+                setStateCount.incrementAndGet();
+                super.setState(state);
+            }
+        };
+        view.setStateListAnimator(stateListAnimator);
+        assertNotNull("State list animator should have a reference to view even if it is detached",
+                stateListAnimator.getTarget());
+        ViewGroup viewGroup = (ViewGroup) getActivity().findViewById(android.R.id.content);
+        int preSetStateCount = setStateCount.get();
+        viewGroup.addView(view);
+        assertTrue("When view is attached, state list drawable's setState should be called",
+                preSetStateCount < setStateCount.get());
+
+        StateListAnimator stateListAnimator2 = new StateListAnimator();
+        view.setStateListAnimator(stateListAnimator2);
+        assertNull("When a new state list animator is assigned, previous one should be detached",
+                stateListAnimator.getTarget());
+        assertNull("Any running animator should be removed on detach",
+                stateListAnimator.getRunningAnimator());
+        assertEquals("The new state list animator should be attached to the view",
+                view, stateListAnimator2.getTarget());
+        viewGroup.removeView(view);
+        assertNotNull("When view is detached from window, state list animator should still keep the"
+                        + " reference",
+                stateListAnimator2.getTarget());
+    }
+
+    public void testStateListLoading() throws InterruptedException {
+        StateListAnimator stateListAnimator = AnimatorInflater
+                .loadStateListAnimator(getActivity(), R.anim.test_state_anim);
+        assertNotNull("A state list animator should be returned", stateListAnimator);
+        assertEquals("Steate list animator should have two items", 3,
+                stateListAnimator.getTuples().size());
+        StateListAnimator.Tuple tuple1 = stateListAnimator.getTuples().get(0);
+        assertEquals("first tuple should have one state", 1, tuple1.getSpecs().length);
+        assertEquals("first spec in tuple 1 should be pressed",
+                com.android.internal.R.attr.state_pressed, tuple1.getSpecs()[0]);
+
+        StateListAnimator.Tuple tuple2 = stateListAnimator.getTuples().get(1);
+        assertEquals("Second tuple should have two specs", 2, tuple2.getSpecs().length);
+        assertTrue("Tuple two should match the expected state",
+                StateSet.stateSetMatches(tuple2.getSpecs(),
+                new int[]{-com.android.internal.R.attr.state_pressed,
+                com.android.internal.R.attr.state_enabled}));
+    }
+}
diff --git a/core/tests/inputmethodtests/run_core_inputmethod_test.sh b/core/tests/inputmethodtests/run_core_inputmethod_test.sh
index 9029ba5..e0f4f6d 100755
--- a/core/tests/inputmethodtests/run_core_inputmethod_test.sh
+++ b/core/tests/inputmethodtests/run_core_inputmethod_test.sh
@@ -21,4 +21,4 @@
   $COMMAND
 fi
 
-adb shell am instrument -w -e class android.os.InputMethodTest,android.os.InputMethodSubtypeArrayTest,android.os.InputMethodSubtypeSwitchingControllerTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner
+adb shell am instrument -w -e class android.os.InputMethodTest,android.os.InputMethodSubtypeArrayTest,android.os.InputMethodSubtypeSwitchingControllerTest,android.os.CursorAnchorInfoTest,android.os.SparseRectFArrayTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner
diff --git a/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
new file mode 100644
index 0000000..59a6314
--- /dev/null
+++ b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.os;
+
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.inputmethod.CursorAnchorInfo;
+import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder;
+
+public class CursorAnchorInfoTest extends InstrumentationTestCase {
+    // null represents a character that is invisible, for example because it's overlapped by some
+    // other UI elements.
+    private static final RectF[] MANY_RECTS = new RectF[] {
+            null,
+            new RectF(102.0f, 202.0f, 302.0f, 402.0f),
+            new RectF(103.0f, 203.0f, 303.0f, 403.0f),
+            new RectF(104.0f, 204.0f, 304.0f, 404.0f),
+            new RectF(105.0f, 205.0f, 305.0f, 405.0f),
+            new RectF(106.0f, 206.0f, 306.0f, 406.0f),
+            null,
+            new RectF(108.0f, 208.0f, 308.0f, 408.0f),
+            new RectF(109.0f, 209.0f, 309.0f, 409.0f),
+            new RectF(110.0f, 210.0f, 310.0f, 410.0f),
+            new RectF(111.0f, 211.0f, 311.0f, 411.0f),
+            new RectF(112.0f, 212.0f, 312.0f, 412.0f),
+            new RectF(113.0f, 213.0f, 313.0f, 413.0f),
+            new RectF(114.0f, 214.0f, 314.0f, 414.0f),
+            new RectF(115.0f, 215.0f, 315.0f, 415.0f),
+            new RectF(116.0f, 216.0f, 316.0f, 416.0f),
+            new RectF(117.0f, 217.0f, 317.0f, 417.0f),
+            null,
+            null,
+    };
+
+    @SmallTest
+    public void testBuilder() throws Exception {
+        final int SELECTION_START = 30;
+        final int SELECTION_END = 40;
+        final int CANDIDATES_START = 32;
+        final int CANDIDATES_END = 33;
+        final float INSERTION_MARKER_HORIZONTAL = 10.5f;
+        final float INSERTION_MARKER_TOP = 100.1f;
+        final float INSERTION_MARKER_BASELINE = 110.4f;
+        final float INSERTION_MARKER_BOTOM = 111.0f;
+        Matrix TRANSFORM_MATRIX = new Matrix(Matrix.IDENTITY_MATRIX);
+        TRANSFORM_MATRIX.setScale(10.0f, 20.0f);
+
+        final CursorAnchorInfoBuilder builder = new CursorAnchorInfoBuilder();
+        builder.setSelectionRange(SELECTION_START, SELECTION_END)
+                .setCandidateRange(CANDIDATES_START, CANDIDATES_END)
+                .setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP,
+                        INSERTION_MARKER_BASELINE, INSERTION_MARKER_BOTOM)
+                .setMatrix(TRANSFORM_MATRIX);
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            if (rect != null) {
+                builder.addCharacterRect(i, rect.left, rect.top, rect.right, rect.bottom);
+            }
+        }
+
+        final CursorAnchorInfo info = builder.build();
+        assertEquals(SELECTION_START, info.getSelectionStart());
+        assertEquals(SELECTION_END, info.getSelectionEnd());
+        assertEquals(CANDIDATES_START, info.getCandidatesStart());
+        assertEquals(CANDIDATES_END, info.getCandidatesEnd());
+        assertEquals(INSERTION_MARKER_HORIZONTAL, info.getInsertionMarkerHorizontal());
+        assertEquals(INSERTION_MARKER_TOP, info.getInsertionMarkerTop());
+        assertEquals(INSERTION_MARKER_BASELINE, info.getInsertionMarkerBaseline());
+        assertEquals(INSERTION_MARKER_BOTOM, info.getInsertionMarkerBottom());
+        assertEquals(TRANSFORM_MATRIX, info.getMatrix());
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            assertEquals(rect, info.getCharacterRect(i));
+        }
+
+        // Make sure that the builder can reproduce the same object.
+        final CursorAnchorInfo info2 = builder.build();
+        assertEquals(SELECTION_START, info2.getSelectionStart());
+        assertEquals(SELECTION_END, info2.getSelectionEnd());
+        assertEquals(CANDIDATES_START, info2.getCandidatesStart());
+        assertEquals(CANDIDATES_END, info2.getCandidatesEnd());
+        assertEquals(INSERTION_MARKER_HORIZONTAL, info2.getInsertionMarkerHorizontal());
+        assertEquals(INSERTION_MARKER_TOP, info2.getInsertionMarkerTop());
+        assertEquals(INSERTION_MARKER_BASELINE, info2.getInsertionMarkerBaseline());
+        assertEquals(INSERTION_MARKER_BOTOM, info2.getInsertionMarkerBottom());
+        assertEquals(TRANSFORM_MATRIX, info2.getMatrix());
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            assertEquals(rect, info2.getCharacterRect(i));
+        }
+        assertEquals(info, info2);
+        assertEquals(info.hashCode(), info2.hashCode());
+
+        // Make sure that object can be marshalled via {@link Parsel}.
+        final CursorAnchorInfo info3 = cloneViaParcel(info2);
+        assertEquals(SELECTION_START, info3.getSelectionStart());
+        assertEquals(SELECTION_END, info3.getSelectionEnd());
+        assertEquals(CANDIDATES_START, info3.getCandidatesStart());
+        assertEquals(CANDIDATES_END, info3.getCandidatesEnd());
+        assertEquals(INSERTION_MARKER_HORIZONTAL, info3.getInsertionMarkerHorizontal());
+        assertEquals(INSERTION_MARKER_TOP, info3.getInsertionMarkerTop());
+        assertEquals(INSERTION_MARKER_BASELINE, info3.getInsertionMarkerBaseline());
+        assertEquals(INSERTION_MARKER_BOTOM, info3.getInsertionMarkerBottom());
+        assertEquals(TRANSFORM_MATRIX, info3.getMatrix());
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            assertEquals(rect, info3.getCharacterRect(i));
+        }
+        assertEquals(info.hashCode(), info3.hashCode());
+
+        builder.reset();
+        final CursorAnchorInfo uninitializedInfo = builder.build();
+        assertEquals(-1, uninitializedInfo.getSelectionStart());
+        assertEquals(-1, uninitializedInfo.getSelectionEnd());
+        assertEquals(-1, uninitializedInfo.getCandidatesStart());
+        assertEquals(-1, uninitializedInfo.getCandidatesEnd());
+        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerHorizontal());
+        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerTop());
+        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBaseline());
+        assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBottom());
+        assertEquals(Matrix.IDENTITY_MATRIX, uninitializedInfo.getMatrix());
+    }
+
+    @SmallTest
+    public void testBuilderAdd() throws Exception {
+        // A negative index should be rejected.
+        try {
+            new CursorAnchorInfoBuilder().addCharacterRect(-1, 0.0f, 0.0f, 0.0f, 0.0f);
+        } catch (IllegalArgumentException ex) {
+            assertTrue(true);
+        }
+    }
+
+    private static CursorAnchorInfo cloneViaParcel(final CursorAnchorInfo src) {
+        Parcel parcel = null;
+        try {
+            parcel = Parcel.obtain();
+            src.writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            return new CursorAnchorInfo(parcel);
+        } finally {
+            if (parcel != null) {
+                parcel.recycle();
+            }
+        }
+    }
+}
+
diff --git a/core/tests/inputmethodtests/src/android/os/SparseRectFArrayTest.java b/core/tests/inputmethodtests/src/android/os/SparseRectFArrayTest.java
new file mode 100644
index 0000000..fae7230
--- /dev/null
+++ b/core/tests/inputmethodtests/src/android/os/SparseRectFArrayTest.java
@@ -0,0 +1,233 @@
+/*
+ * 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.os;
+
+import android.graphics.RectF;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.inputmethod.SparseRectFArray;
+import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder;
+
+import java.util.Objects;
+
+public class SparseRectFArrayTest extends InstrumentationTestCase {
+    // A test data for {@link SparseRectFArray}. null represents the gap of indices.
+    private static final RectF[] MANY_RECTS = new RectF[] {
+            null,
+            new RectF(102.0f, 202.0f, 302.0f, 402.0f),
+            new RectF(103.0f, 203.0f, 303.0f, 403.0f),
+            new RectF(104.0f, 204.0f, 304.0f, 404.0f),
+            new RectF(105.0f, 205.0f, 305.0f, 405.0f),
+            new RectF(106.0f, 206.0f, 306.0f, 406.0f),
+            null,
+            new RectF(108.0f, 208.0f, 308.0f, 408.0f),
+            new RectF(109.0f, 209.0f, 309.0f, 409.0f),
+            new RectF(110.0f, 210.0f, 310.0f, 410.0f),
+            new RectF(111.0f, 211.0f, 311.0f, 411.0f),
+            new RectF(112.0f, 212.0f, 312.0f, 412.0f),
+            new RectF(113.0f, 213.0f, 313.0f, 413.0f),
+            new RectF(114.0f, 214.0f, 314.0f, 414.0f),
+            new RectF(115.0f, 215.0f, 315.0f, 415.0f),
+            new RectF(116.0f, 216.0f, 316.0f, 416.0f),
+            new RectF(117.0f, 217.0f, 317.0f, 417.0f),
+            null,
+            null,
+            new RectF(118.0f, 218.0f, 318.0f, 418.0f),
+    };
+
+    @SmallTest
+    public void testBuilder() throws Exception {
+        final RectF TEMP_RECT = new RectF(10.0f, 20.0f, 30.0f, 40.0f);
+
+        final SparseRectFArrayBuilder builder = new SparseRectFArrayBuilder();
+        builder.append(100, TEMP_RECT.left, TEMP_RECT.top, TEMP_RECT.right, TEMP_RECT.bottom);
+        assertNull(builder.build().get(-1));
+        assertNull(builder.build().get(0));
+        assertNull(builder.build().get(99));
+        assertEquals(TEMP_RECT, builder.build().get(100));
+        assertNull(builder.build().get(101));
+
+        // Test if {@link SparseRectFArrayBuilder#reset} resets its internal state.
+        builder.reset();
+        assertNull(builder.build().get(100));
+
+        builder.reset();
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            if (rect != null) {
+                builder.append(i, rect.left, rect.top, rect.right, rect.bottom);
+            }
+        }
+        final SparseRectFArray array = builder.build();
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            assertEquals(rect, array.get(i));
+        }
+
+        // Make sure the builder reproduces an equivalent object.
+        final SparseRectFArray array2 = builder.build();
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            assertEquals(rect, array2.get(i));
+        }
+        assertEqualRects(array, array2);
+
+        // Make sure the instance can be marshaled via {@link Parcel}.
+        final SparseRectFArray array3 = cloneViaParcel(array);
+        for (int i = 0; i < MANY_RECTS.length; i++) {
+            final RectF rect = MANY_RECTS[i];
+            assertEquals(rect, array3.get(i));
+        }
+        assertEqualRects(array, array3);
+
+        // Make sure the builder can be reset.
+        builder.reset();
+        assertNull(builder.build().get(0));
+    }
+
+    @SmallTest
+    public void testEquality() throws Exception {
+        // Empty array should be equal.
+        assertEqualRects(new SparseRectFArrayBuilder().build(),
+                new SparseRectFArrayBuilder().build());
+
+        assertEqualRects(
+                new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(),
+                new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(),
+                new SparseRectFArrayBuilder().append(100, 2.0f, 2.0f, 3.0f, 4.0f).build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(),
+                new SparseRectFArrayBuilder().append(101, 1.0f, 2.0f, 3.0f, 4.0f).build());
+
+        assertEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(),
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(),
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(),
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f).build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(),
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 1.0f, 0.0f, 0.0f, 0.0f).build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 1.0f, 0.0f, 0.0f, 0.0f).build(),
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(),
+                new SparseRectFArrayBuilder()
+                        .append(100, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(102, 0.0f, 0.0f, 0.0f, 0.0f).build());
+
+        assertEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(1, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(1000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .build(),
+                new SparseRectFArrayBuilder()
+                        .append(1, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(1000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .build());
+
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(1, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(1000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .build(),
+                new SparseRectFArrayBuilder()
+                        .append(1, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .build());
+        assertNotEqualRects(
+                new SparseRectFArrayBuilder()
+                        .append(1, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(1000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .build(),
+                new SparseRectFArrayBuilder()
+                        .append(1, 1.0f, 2.0f, 3.0f, 4.0f)
+                        .append(1000, 1.0f, 0.0f, 0.0f, 0.0f)
+                        .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f)
+                        .build());
+    }
+
+    @SmallTest
+    public void testBuilderAppend() throws Exception {
+        // Key should be appended in ascending order.
+        try {
+            new SparseRectFArrayBuilder().append(10, 0, 0, 0, 0).append(0, 1, 2, 3, 4);
+        } catch (IllegalArgumentException ex) {
+            assertTrue(true);
+        }
+
+        try {
+            new SparseRectFArrayBuilder().append(10, 0, 0, 0, 0).append(10, 1, 2, 3, 4);
+        } catch (IllegalArgumentException ex) {
+            assertTrue(true);
+        }
+    }
+
+    private static void assertEqualRects(SparseRectFArray a, SparseRectFArray b) {
+        assertEquals(a, b);
+        if (a != null && b != null) {
+            assertEquals(a.hashCode(), b.hashCode());
+        }
+    }
+
+    private static void assertNotEqualRects(SparseRectFArray a, SparseRectFArray b) {
+        assertFalse(Objects.equals(a, b));
+    }
+
+    private static SparseRectFArray cloneViaParcel(final SparseRectFArray src) {
+        Parcel parcel = null;
+        try {
+            parcel = Parcel.obtain();
+            src.writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            return new SparseRectFArray(parcel);
+        } finally {
+            if (parcel != null) {
+                parcel.recycle();
+            }
+        }
+    }
+}
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index 4057736..6143b4b 100644
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -584,9 +584,14 @@
 </tr>
 <tr>
   <td><code>android.hardware.camera.any</code></td>
-  <td>The application uses at least one camera facing in any direction. Use this
-in preference to <code>android.hardware.camera</code> if a back-facing camera is
-not required.</td>
+  <td>The application uses at least one camera facing in any direction, or an
+external camera device if one is connected. Use this in preference to
+<code>android.hardware.camera</code> if a back-facing camera is not required.
+  </td>
+</tr>
+<tr>
+  <td><code>android.hardware.camera.external</code></td>
+  <td>The application uses an external camera device if one is connected.</td>
 </tr>
 
 <tr>
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index 3b1292e..59c2269 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -16,6 +16,7 @@
       <li><a href="#Required">Required notification contents</a></li>
       <li><a href="#Optional">Optional notification contents and settings</a></li>
       <li><a href="#Actions">Notification actions</a></li>
+      <li><a href="#Priority">Notification priority</a></li>
       <li><a href="#SimpleNotification">Creating a simple notification</a></li>
       <li><a href="#ApplyStyle">Applying a big view style to a notification</a></li>
       <li><a href="#Compatibility">Handling compatibility</a></li>
@@ -290,6 +291,26 @@
     {@link android.support.v4.app.NotificationCompat.Builder}.
 </p>
 <!-- ------------------------------------------------------------------------------------------ -->
+<h3 id="Priority">Notification priority</h3>
+<p>
+    If you wish, you can set the priority of a notification. The priority acts
+    as a hint to the device UI about how the notification should be displayed.
+    To set a notification's priority, call {@link
+    android.support.v4.app.NotificationCompat.Builder#setPriority(int)
+    NotificationCompat.Builder.setPriority()} and pass in one of the {@link
+    android.support.v4.app.NotificationCompat} priority constants. There are
+    five priority levels, ranging from {@link
+    android.support.v4.app.NotificationCompat#PRIORITY_MIN} (-2) to {@link
+    android.support.v4.app.NotificationCompat#PRIORITY_MAX} (2); if not set, the
+    priority defaults to {@link
+    android.support.v4.app.NotificationCompat#PRIORITY_DEFAULT} (0).
+</p>
+<p> For information about setting an appropriate priority level, see "Correctly
+    set and manage notification priority" in the <a
+    href="{@docRoot}design/patterns/notifications.html">Notifications</a> Design
+    guide.
+</p>
+<!-- ------------------------------------------------------------------------------------------ -->
 <h3 id="SimpleNotification">Creating a simple notification</h3>
 <p>
     The following snippet illustrates a simple notification that specifies an activity to open when
diff --git a/graphics/java/android/graphics/Camera.java b/graphics/java/android/graphics/Camera.java
index c263a84..a40085b 100644
--- a/graphics/java/android/graphics/Camera.java
+++ b/graphics/java/android/graphics/Camera.java
@@ -154,7 +154,7 @@
             getMatrix(mMatrix);
             canvas.concat(mMatrix);
         } else {
-            nativeApplyToCanvas(canvas.mNativeCanvas);
+            nativeApplyToCanvas(canvas.getNativeCanvas());
         }
     }
 
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index ae3eae1..5b18623 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -39,8 +39,12 @@
 public class Canvas {
 
     // assigned in constructors or setBitmap, freed in finalizer
+    private long mNativeCanvas;
+
     /** @hide */
-    public long mNativeCanvas;
+    public long getNativeCanvas() {
+        return mNativeCanvas;
+    }
 
     // may be null
     private Bitmap mBitmap;
diff --git a/graphics/java/android/graphics/CanvasProperty.java b/graphics/java/android/graphics/CanvasProperty.java
index 99ea9b1..be86060 100644
--- a/graphics/java/android/graphics/CanvasProperty.java
+++ b/graphics/java/android/graphics/CanvasProperty.java
@@ -16,12 +16,15 @@
 
 package android.graphics;
 
+import com.android.internal.util.VirtualRefBasePtr;
+
 /**
  * TODO: Make public?
  * @hide
  */
 public final class CanvasProperty<T> {
-    private long mNativeContainer;
+
+    private VirtualRefBasePtr mProperty;
 
     public static CanvasProperty<Float> createFloat(float initialValue) {
         return new CanvasProperty<Float>(nCreateFloat(initialValue));
@@ -32,25 +35,14 @@
     }
 
     private CanvasProperty(long nativeContainer) {
-        mNativeContainer = nativeContainer;
+        mProperty = new VirtualRefBasePtr(nativeContainer);
     }
 
     /** @hide */
     public long getNativeContainer() {
-        return mNativeContainer;
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            nUnref(mNativeContainer);
-            mNativeContainer = 0;
-        } finally {
-            super.finalize();
-        }
+        return mProperty.get();
     }
 
     private static native long nCreateFloat(float initialValue);
     private static native long nCreatePaint(long initialValuePaintPtr);
-    private static native void nUnref(long ptr);
 }
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 69089b1..6ff5f4f 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -164,12 +164,12 @@
     }
 
     void drawSoftware(Canvas canvas, RectF location, Paint paint) {
-        nativeDraw(canvas.mNativeCanvas, location, mBitmap.ni(), mNativeChunk,
+        nativeDraw(canvas.getNativeCanvas(), location, mBitmap.ni(), mNativeChunk,
                 paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
     }
 
     void drawSoftware(Canvas canvas, Rect location, Paint paint) {
-        nativeDraw(canvas.mNativeCanvas, location, mBitmap.ni(), mNativeChunk,
+        nativeDraw(canvas.getNativeCanvas(), location, mBitmap.ni(), mNativeChunk,
                 paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
     }
 
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 1e1128e..457b3ea 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -55,27 +55,6 @@
     /**
      * @hide
      */
-    public boolean hasShadow;
-    /**
-     * @hide
-     */
-    public float shadowDx;
-    /**
-     * @hide
-     */
-    public float shadowDy;
-    /**
-     * @hide
-     */
-    public float shadowRadius;
-    /**
-     * @hide
-     */
-    public int shadowColor;
-
-    /**
-     * @hide
-     */
     public  int         mBidiFlags = BIDI_DEFAULT_LTR;
     
     static final Style[] sStyleArray = {
@@ -492,12 +471,6 @@
         mCompatScaling = 1;
         mInvCompatScaling = 1;
 
-        hasShadow = false;
-        shadowDx = 0;
-        shadowDy = 0;
-        shadowRadius = 0;
-        shadowColor = 0;
-
         mBidiFlags = BIDI_DEFAULT_LTR;
         setTextLocale(Locale.getDefault());
         setElegantTextHeight(false);
@@ -538,12 +511,6 @@
         mCompatScaling = paint.mCompatScaling;
         mInvCompatScaling = paint.mInvCompatScaling;
 
-        hasShadow = paint.hasShadow;
-        shadowDx = paint.shadowDx;
-        shadowDy = paint.shadowDy;
-        shadowRadius = paint.shadowRadius;
-        shadowColor = paint.shadowColor;
-
         mBidiFlags = paint.mBidiFlags;
         mLocale = paint.mLocale;
     }
@@ -1135,22 +1102,24 @@
      * layer is removed.
      */
     public void setShadowLayer(float radius, float dx, float dy, int color) {
-        hasShadow = radius > 0.0f;
-        shadowRadius = radius;
-        shadowDx = dx;
-        shadowDy = dy;
-        shadowColor = color;
-        nSetShadowLayer(radius, dx, dy, color);
+      native_setShadowLayer(mNativePaint, radius, dx, dy, color);
     }
-    
-    private native void nSetShadowLayer(float radius, float dx, float dy, int color);
 
     /**
      * Clear the shadow layer.
      */
     public void clearShadowLayer() {
-        hasShadow = false;
-        nSetShadowLayer(0, 0, 0, 0);
+        setShadowLayer(0, 0, 0, 0);
+    }
+
+    /**
+     * Checks if the paint has a shadow layer attached
+     *
+     * @return true if the paint has a shadow layer attached and false otherwise
+     * @hide
+     */
+    public boolean hasShadowLayer() {
+      return native_hasShadowLayer(mNativePaint);
     }
 
     /**
@@ -2295,4 +2264,8 @@
     private static native void nativeGetCharArrayBounds(long nativePaint,
                                 char[] text, int index, int count, int bidiFlags, Rect bounds);
     private static native void finalizer(long nativePaint);
+
+    private static native void native_setShadowLayer(long native_object,
+            float radius, float dx, float dy, int color);
+    private static native boolean native_hasShadowLayer(long native_object);
 }
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index 25188e0..a16c099 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -107,7 +107,7 @@
         if (mRecordingCanvas != null) {
             endRecording();
         }
-        nativeDraw(canvas.mNativeCanvas, mNativePicture);
+        nativeDraw(canvas.getNativeCanvas(), mNativePicture);
     }
 
     /**
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 3f8c45c..0862cdd 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -18,6 +18,7 @@
 
 import java.lang.ref.WeakReference;
 
+import android.annotation.Nullable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -132,14 +133,14 @@
      * Register a callback to be invoked when a new image frame becomes available to the
      * SurfaceTexture.
      * <p>
-     * This callback may be called on an arbitrary thread, so it is not
+     * The callback may be called on an arbitrary thread, so it is not
      * safe to call {@link #updateTexImage} without first binding the OpenGL ES context to the
      * thread invoking the callback.
      * </p>
      *
-     * @param listener The listener to set.
+     * @param listener The listener to use, or null to remove the listener.
      */
-    public void setOnFrameAvailableListener(OnFrameAvailableListener listener) {
+    public void setOnFrameAvailableListener(@Nullable OnFrameAvailableListener listener) {
         setOnFrameAvailableListener(listener, null);
     }
 
@@ -147,17 +148,18 @@
      * Register a callback to be invoked when a new image frame becomes available to the
      * SurfaceTexture.
      * <p>
-     * If no handler is specified, then this callback may be called on an arbitrary thread,
+     * If a handler is specified, the callback will be invoked on that handler's thread.
+     * If no handler is specified, then the callback may be called on an arbitrary thread,
      * so it is not safe to call {@link #updateTexImage} without first binding the OpenGL ES
      * context to the thread invoking the callback.
      * </p>
      *
-     * @param listener The listener to set.
+     * @param listener The listener to use, or null to remove the listener.
      * @param handler The handler on which the listener should be invoked, or null
      * to use an arbitrary thread.
      */
-    public void setOnFrameAvailableListener(final OnFrameAvailableListener listener,
-            Handler handler) {
+    public void setOnFrameAvailableListener(@Nullable final OnFrameAvailableListener listener,
+            @Nullable Handler handler) {
         if (listener != null) {
             // Although we claim the thread is arbitrary, earlier implementation would
             // prefer to send the callback on the creating looper or the main looper
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
new file mode 100644
index 0000000..46e3401
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -0,0 +1,524 @@
+/*
+ * 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.drawable;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.LongSparseLongArray;
+import android.util.SparseIntArray;
+import android.util.StateSet;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * Drawable containing a set of Drawable keyframes where the currently displayed
+ * keyframe is chosen based on the current state set. Animations between
+ * keyframes may optionally be defined using transition elements.
+ * <p>
+ * This drawable can be defined in an XML file with the <code>
+ * &lt;animated-selector></code> element. Each keyframe Drawable is defined in a
+ * nested <code>&lt;item></code> element. Transitions are defined in a nested
+ * <code>&lt;transition></code> element.
+ *
+ * @attr ref android.R.styleable#DrawableStates_state_focused
+ * @attr ref android.R.styleable#DrawableStates_state_window_focused
+ * @attr ref android.R.styleable#DrawableStates_state_enabled
+ * @attr ref android.R.styleable#DrawableStates_state_checkable
+ * @attr ref android.R.styleable#DrawableStates_state_checked
+ * @attr ref android.R.styleable#DrawableStates_state_selected
+ * @attr ref android.R.styleable#DrawableStates_state_activated
+ * @attr ref android.R.styleable#DrawableStates_state_active
+ * @attr ref android.R.styleable#DrawableStates_state_single
+ * @attr ref android.R.styleable#DrawableStates_state_first
+ * @attr ref android.R.styleable#DrawableStates_state_middle
+ * @attr ref android.R.styleable#DrawableStates_state_last
+ * @attr ref android.R.styleable#DrawableStates_state_pressed
+ */
+public class AnimatedStateListDrawable extends StateListDrawable {
+    private static final String ELEMENT_TRANSITION = "transition";
+    private static final String ELEMENT_ITEM = "item";
+
+    private AnimatedStateListState mState;
+
+    /** The currently running animation, if any. */
+    private ObjectAnimator mAnim;
+
+    /** Index to be set after the animation ends. */
+    private int mAnimToIndex = -1;
+
+    /** Index away from which we are animating. */
+    private int mAnimFromIndex = -1;
+
+    private boolean mMutated;
+
+    public AnimatedStateListDrawable() {
+        this(null, null);
+    }
+
+    /**
+     * Add a new drawable to the set of keyframes.
+     *
+     * @param stateSet An array of resource IDs to associate with the keyframe
+     * @param drawable The drawable to show when in the specified state
+     * @param id The unique identifier for the keyframe
+     */
+    public void addState(int[] stateSet, Drawable drawable, int id) {
+        if (drawable != null) {
+            mState.addStateSet(stateSet, drawable, id);
+            onStateChange(getState());
+        }
+    }
+
+    /**
+     * Adds a new transition between keyframes.
+     *
+     * @param fromId Unique identifier of the starting keyframe
+     * @param toId Unique identifier of the ending keyframe
+     * @param anim An AnimationDrawable to use as a transition
+     * @param reversible Whether the transition can be reversed
+     */
+    public void addTransition(int fromId, int toId, AnimationDrawable anim, boolean reversible) {
+        mState.addTransition(fromId, toId, anim, reversible);
+    }
+
+    @Override
+    public boolean isStateful() {
+        return true;
+    }
+
+    @Override
+    protected boolean onStateChange(int[] stateSet) {
+        final int keyframeIndex = mState.indexOfKeyframe(stateSet);
+        if (keyframeIndex == getCurrentIndex()) {
+            return false;
+        }
+
+        if (selectTransition(keyframeIndex)) {
+            return true;
+        }
+
+        if (selectDrawable(keyframeIndex)) {
+            return true;
+        }
+
+        return super.onStateChange(stateSet);
+    }
+
+    private boolean selectTransition(int toIndex) {
+        if (mAnim != null) {
+            if (toIndex == mAnimToIndex) {
+                // Already animating to that keyframe.
+                return true;
+            } else if (toIndex == mAnimFromIndex) {
+                // Reverse the current animation.
+                mAnim.reverse();
+                mAnimFromIndex = mAnimToIndex;
+                mAnimToIndex = toIndex;
+                return true;
+            }
+
+            // Changing animation, end the current animation.
+            mAnim.end();
+        }
+
+        final AnimatedStateListState state = mState;
+        final int fromIndex = getCurrentIndex();
+        final int fromId = state.getKeyframeIdAt(fromIndex);
+        final int toId = state.getKeyframeIdAt(toIndex);
+
+        if (toId == 0 || fromId == 0) {
+            // Missing a keyframe ID.
+            return false;
+        }
+
+        final int transitionIndex = state.indexOfTransition(fromId, toId);
+        if (transitionIndex < 0 || !selectDrawable(transitionIndex)) {
+            // Couldn't select a transition.
+            return false;
+        }
+
+        final Drawable d = getCurrent();
+        if (!(d instanceof AnimationDrawable)) {
+            // Transition isn't an animation.
+            return false;
+        }
+
+        final AnimationDrawable ad = (AnimationDrawable) d;
+        final boolean reversed = mState.isTransitionReversed(fromId, toId);
+        final int frameCount = ad.getNumberOfFrames();
+        final int fromFrame = reversed ? frameCount - 1 : 0;
+        final int toFrame = reversed ? 0 : frameCount - 1;
+
+        final FrameInterpolator interp = new FrameInterpolator(ad, reversed);
+        final ObjectAnimator anim = ObjectAnimator.ofInt(ad, "currentIndex", fromFrame, toFrame);
+        anim.setAutoCancel(true);
+        anim.setDuration(interp.getTotalDuration());
+        anim.addListener(mAnimListener);
+        anim.setInterpolator(interp);
+        anim.start();
+
+        mAnim = anim;
+        mAnimFromIndex = fromIndex;
+        mAnimToIndex = toIndex;
+        return true;
+    }
+
+    @Override
+    public void jumpToCurrentState() {
+        super.jumpToCurrentState();
+
+        if (mAnim != null) {
+            mAnim.end();
+        }
+    }
+
+    @Override
+    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+            throws XmlPullParserException, IOException {
+        final TypedArray a = r.obtainAttributes(attrs, R.styleable.AnimatedStateListDrawable);
+
+        super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedStateListDrawable_visible);
+
+        final StateListState stateListState = getStateListState();
+        stateListState.setVariablePadding(a.getBoolean(
+                R.styleable.AnimatedStateListDrawable_variablePadding, false));
+        stateListState.setConstantSize(a.getBoolean(
+                R.styleable.AnimatedStateListDrawable_constantSize, false));
+        stateListState.setEnterFadeDuration(a.getInt(
+                R.styleable.AnimatedStateListDrawable_enterFadeDuration, 0));
+        stateListState.setExitFadeDuration(a.getInt(
+                R.styleable.AnimatedStateListDrawable_exitFadeDuration, 0));
+
+        setDither(a.getBoolean(R.styleable.AnimatedStateListDrawable_dither, true));
+        setAutoMirrored(a.getBoolean(R.styleable.AnimatedStateListDrawable_autoMirrored, false));
+
+        a.recycle();
+
+        int type;
+
+        final int innerDepth = parser.getDepth() + 1;
+        int depth;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && ((depth = parser.getDepth()) >= innerDepth
+                || type != XmlPullParser.END_TAG)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if (depth > innerDepth) {
+                continue;
+            }
+
+            if (parser.getName().equals(ELEMENT_ITEM)) {
+                parseItem(r, parser, attrs, theme);
+            } else if (parser.getName().equals(ELEMENT_TRANSITION)) {
+                parseTransition(r, parser, attrs, theme);
+            }
+        }
+
+        onStateChange(getState());
+    }
+
+    private int parseTransition(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+            throws XmlPullParserException, IOException {
+        int drawableRes = 0;
+        int fromId = 0;
+        int toId = 0;
+        boolean reversible = false;
+
+        final int numAttrs = attrs.getAttributeCount();
+        for (int i = 0; i < numAttrs; i++) {
+            final int stateResId = attrs.getAttributeNameResource(i);
+            switch (stateResId) {
+                case 0:
+                    break;
+                case R.attr.fromId:
+                    fromId = attrs.getAttributeResourceValue(i, 0);
+                    break;
+                case R.attr.toId:
+                    toId = attrs.getAttributeResourceValue(i, 0);
+                    break;
+                case R.attr.drawable:
+                    drawableRes = attrs.getAttributeResourceValue(i, 0);
+                    break;
+                case R.attr.reversible:
+                    reversible = attrs.getAttributeBooleanValue(i, false);
+                    break;
+            }
+        }
+
+        final Drawable dr;
+        if (drawableRes != 0) {
+            dr = r.getDrawable(drawableRes);
+        } else {
+            int type;
+            while ((type = parser.next()) == XmlPullParser.TEXT) {
+            }
+            if (type != XmlPullParser.START_TAG) {
+                throw new XmlPullParserException(
+                        parser.getPositionDescription()
+                                + ": <item> tag requires a 'drawable' attribute or "
+                                + "child tag defining a drawable");
+            }
+            dr = Drawable.createFromXmlInnerThemed(r, parser, attrs, theme);
+        }
+
+        final AnimationDrawable anim;
+        if (dr instanceof AnimationDrawable) {
+            anim = (AnimationDrawable) dr;
+        } else {
+            throw new XmlPullParserException(parser.getPositionDescription()
+                    + ": <transition> tag requires a 'drawable' attribute or "
+                    + "child tag defining a drawable of type <animation>");
+        }
+
+        return mState.addTransition(fromId, toId, anim, reversible);
+    }
+
+    private int parseItem(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+            throws XmlPullParserException, IOException {
+        int drawableRes = 0;
+        int keyframeId = 0;
+
+        int j = 0;
+        final int numAttrs = attrs.getAttributeCount();
+        int[] states = new int[numAttrs];
+        for (int i = 0; i < numAttrs; i++) {
+            final int stateResId = attrs.getAttributeNameResource(i);
+            switch (stateResId) {
+                case 0:
+                    break;
+                case R.attr.id:
+                    keyframeId = attrs.getAttributeResourceValue(i, 0);
+                    break;
+                case R.attr.drawable:
+                    drawableRes = attrs.getAttributeResourceValue(i, 0);
+                    break;
+                default:
+                    final boolean hasState = attrs.getAttributeBooleanValue(i, false);
+                    states[j++] = hasState ? stateResId : -stateResId;
+            }
+        }
+        states = StateSet.trimStateSet(states, j);
+
+        final Drawable dr;
+        if (drawableRes != 0) {
+            dr = r.getDrawable(drawableRes);
+        } else {
+            int type;
+            while ((type = parser.next()) == XmlPullParser.TEXT) {
+            }
+            if (type != XmlPullParser.START_TAG) {
+                throw new XmlPullParserException(
+                        parser.getPositionDescription()
+                                + ": <item> tag requires a 'drawable' attribute or "
+                                + "child tag defining a drawable");
+            }
+            dr = Drawable.createFromXmlInnerThemed(r, parser, attrs, theme);
+        }
+
+        return mState.addStateSet(states, dr, keyframeId);
+    }
+
+    @Override
+    public Drawable mutate() {
+        if (!mMutated) {
+            final AnimatedStateListState newState = new AnimatedStateListState(mState, this, null);
+            setConstantState(newState);
+            mMutated = true;
+        }
+
+        return this;
+    }
+
+    private final AnimatorListenerAdapter mAnimListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator anim) {
+            selectDrawable(mAnimToIndex);
+
+            mAnimToIndex = -1;
+            mAnimFromIndex = -1;
+            mAnim = null;
+        }
+    };
+
+    static class AnimatedStateListState extends StateListState {
+        private static final int REVERSE_SHIFT = 32;
+        private static final int REVERSE_MASK = 0x1;
+
+        final LongSparseLongArray mTransitions;
+        final SparseIntArray mStateIds;
+
+        AnimatedStateListState(AnimatedStateListState orig, AnimatedStateListDrawable owner,
+                Resources res) {
+            super(orig, owner, res);
+
+            if (orig != null) {
+                mTransitions = orig.mTransitions.clone();
+                mStateIds = orig.mStateIds.clone();
+            } else {
+                mTransitions = new LongSparseLongArray();
+                mStateIds = new SparseIntArray();
+            }
+        }
+
+        int addTransition(int fromId, int toId, AnimationDrawable anim, boolean reversible) {
+            final int pos = super.addChild(anim);
+            final long keyFromTo = generateTransitionKey(fromId, toId);
+            mTransitions.append(keyFromTo, pos);
+
+            if (reversible) {
+                final long keyToFrom = generateTransitionKey(toId, fromId);
+                mTransitions.append(keyToFrom, pos | (1L << REVERSE_SHIFT));
+            }
+
+            return addChild(anim);
+        }
+
+        int addStateSet(int[] stateSet, Drawable drawable, int id) {
+            final int index = super.addStateSet(stateSet, drawable);
+            mStateIds.put(index, id);
+            return index;
+        }
+
+        int indexOfKeyframe(int[] stateSet) {
+            final int index = super.indexOfStateSet(stateSet);
+            if (index >= 0) {
+                return index;
+            }
+
+            return super.indexOfStateSet(StateSet.WILD_CARD);
+        }
+
+        int getKeyframeIdAt(int index) {
+            return index < 0 ? 0 : mStateIds.get(index, 0);
+        }
+
+        int indexOfTransition(int fromId, int toId) {
+            final long keyFromTo = generateTransitionKey(fromId, toId);
+            return (int) mTransitions.get(keyFromTo, -1);
+        }
+
+        boolean isTransitionReversed(int fromId, int toId) {
+            final long keyFromTo = generateTransitionKey(fromId, toId);
+            return (mTransitions.get(keyFromTo, -1) >> REVERSE_SHIFT & REVERSE_MASK) == 1;
+        }
+
+        @Override
+        public Drawable newDrawable() {
+            return new AnimatedStateListDrawable(this, null);
+        }
+
+        @Override
+        public Drawable newDrawable(Resources res) {
+            return new AnimatedStateListDrawable(this, res);
+        }
+
+        private static long generateTransitionKey(int fromId, int toId) {
+            return (long) fromId << 32 | toId;
+        }
+    }
+
+    void setConstantState(AnimatedStateListState state) {
+        super.setConstantState(state);
+
+        mState = state;
+    }
+
+    private AnimatedStateListDrawable(AnimatedStateListState state, Resources res) {
+        super(null);
+
+        final AnimatedStateListState newState = new AnimatedStateListState(state, this, res);
+        setConstantState(newState);
+        onStateChange(getState());
+        jumpToCurrentState();
+    }
+
+    /**
+     * Interpolates between frames with respect to their individual durations.
+     */
+    private static class FrameInterpolator implements TimeInterpolator {
+        private int[] mFrameTimes;
+        private int mFrames;
+        private int mTotalDuration;
+
+        public FrameInterpolator(AnimationDrawable d, boolean reversed) {
+            updateFrames(d, reversed);
+        }
+
+        public int updateFrames(AnimationDrawable d, boolean reversed) {
+            final int N = d.getNumberOfFrames();
+            mFrames = N;
+
+            if (mFrameTimes == null || mFrameTimes.length < N) {
+                mFrameTimes = new int[N];
+            }
+
+            final int[] frameTimes = mFrameTimes;
+            int totalDuration = 0;
+            for (int i = 0; i < N; i++) {
+                final int duration = d.getDuration(reversed ? N - i - 1 : i);
+                frameTimes[i] = duration;
+                totalDuration += duration;
+            }
+
+            mTotalDuration = totalDuration;
+            return totalDuration;
+        }
+
+        public int getTotalDuration() {
+            return mTotalDuration;
+        }
+
+        @Override
+        public float getInterpolation(float input) {
+            final int elapsed = (int) (input * mTotalDuration + 0.5f);
+            final int N = mFrames;
+            final int[] frameTimes = mFrameTimes;
+
+            // Find the current frame and remaining time within that frame.
+            int remaining = elapsed;
+            int i = 0;
+            while (i < N && remaining >= frameTimes[i]) {
+                remaining -= frameTimes[i];
+                i++;
+            }
+
+            // Remaining time is relative of total duration.
+            final float frameElapsed;
+            if (i < N) {
+                frameElapsed = remaining / (float) mTotalDuration;
+            } else {
+                frameElapsed = 0;
+            }
+
+            return i / (float) N + frameElapsed;
+        }
+    }
+}
+
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 3f94e26..da4bc10 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -94,7 +94,7 @@
         boolean changed = super.setVisible(visible, restart);
         if (visible) {
             if (changed || restart) {
-                setFrame(0, true, true);
+                setFrame(0, true, mCurFrame >= 0);
             }
         } else {
             unscheduleSelf(this);
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index b9d5e19..b939636 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1039,6 +1039,8 @@
         final String name = parser.getName();
         if (name.equals("selector")) {
             drawable = new StateListDrawable();
+        } else if (name.equals("animated-selector")) {
+            drawable = new AnimatedStateListDrawable();
         } else if (name.equals("level-list")) {
             drawable = new LevelListDrawable();
         } else if (name.equals("layer-list")) {
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 1f8b51d..08fc99d 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -359,6 +359,16 @@
                 mDrawableContainerState.getOpacity();
     }
 
+    /** @hide */
+    public void setCurrentIndex(int index) {
+        selectDrawable(index);
+    }
+
+    /** @hide */
+    public int getCurrentIndex() {
+        return mCurIndex;
+    }
+
     public boolean selectDrawable(int idx) {
         if (idx == mCurIndex) {
             return false;
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 61b1b85..99ab4dd 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -237,7 +237,7 @@
         paint.setAlpha(modulateAlpha(prevAlpha, state.mAlpha));
 
         // only draw shape if it may affect output
-        if (paint.getAlpha() != 0 || paint.getXfermode() != null || paint.hasShadow) {
+        if (paint.getAlpha() != 0 || paint.getXfermode() != null || paint.hasShadowLayer()) {
             final boolean clearColorFilter;
             if (mTintFilter != null && paint.getColorFilter() == null) {
                 paint.setColorFilter(mTintFilter);
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 271af2b..f22a063 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -55,8 +55,9 @@
  * @attr ref android.R.styleable#DrawableStates_state_pressed
  */
 public class StateListDrawable extends DrawableContainer {
+    private static final String TAG = StateListDrawable.class.getSimpleName();
+
     private static final boolean DEBUG = false;
-    private static final String TAG = "StateListDrawable";
 
     /**
      * To be proper, we should have a getter for dither (and alpha, etc.)
@@ -69,7 +70,8 @@
      * to improve the quality at negligible cost.
      */
     private static final boolean DEFAULT_DITHER = true;
-    private final StateListState mStateListState;
+
+    private StateListState mStateListState;
     private boolean mMutated;
 
     public StateListDrawable() {
@@ -274,7 +276,7 @@
         mStateListState.setLayoutDirection(layoutDirection);
     }
 
-    static final class StateListState extends DrawableContainerState {
+    static class StateListState extends DrawableContainerState {
         int[][] mStateSets;
 
         StateListState(StateListState orig, StateListDrawable owner, Resources res) {
@@ -293,7 +295,7 @@
             return pos;
         }
 
-        private int indexOfStateSet(int[] stateSet) {
+        int indexOfStateSet(int[] stateSet) {
             final int[][] stateSets = mStateSets;
             final int N = getChildCount();
             for (int i = 0; i < N; i++) {
@@ -323,11 +325,26 @@
         }
     }
 
+    void setConstantState(StateListState state) {
+        super.setConstantState(state);
+
+        mStateListState = state;
+    }
+
     private StateListDrawable(StateListState state, Resources res) {
-        StateListState as = new StateListState(state, this, res);
-        mStateListState = as;
-        setConstantState(as);
+        final StateListState newState = new StateListState(state, this, res);
+        setConstantState(newState);
         onStateChange(getState());
     }
+
+    /**
+     * This constructor exists so subclasses can avoid calling the default
+     * constructor and setting up a StateListDrawable-specific constant state.
+     */
+    StateListDrawable(StateListState state) {
+        if (state != null) {
+            setConstantState(state);
+        }
+    }
 }
 
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 77712b6..ff4ab98 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -14,8 +14,6 @@
 
 package android.graphics.drawable;
 
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
@@ -31,9 +29,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
 
 import com.android.internal.R;
 
@@ -46,7 +41,6 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 
 /**
  * This lets you create a drawable based on an XML vector graphic It can be
@@ -56,8 +50,6 @@
  * <p/>
  * <dl>
  * <dt><code>&lt;vector></code></dt>
- * <dd>The attribute <code>android:trigger</code> defines a state change that
- * will drive the animation</dd>
  * <dd>The attribute <code>android:versionCode</code> defines the version of
  * VectorDrawable</dd>
  * <dt><code>&lt;size></code></dt>
@@ -68,8 +60,7 @@
  * The size is defined using the attributes <code>android:viewportHeight</code>
  * <code>android:viewportWidth</code></dd>
  * <dt><code>&lt;group></code></dt>
- * <dd>Defines a "key frame" in the animation if there is only one group the
- * drawable is static 2D image that has no animation.</dd>
+ * <dd>Defines the static 2D image.</dd>
  * <dt><code>&lt;path></code></dt>
  * <dd>Defines paths to be drawn. The path elements must be within a group
  * <dl>
@@ -109,48 +100,6 @@
  * <dd>Sets the lineJoin for a stroked path: miter,round,bevel</dd></dt>
  * <dt><code>android:strokeMiterLimit</code>
  * <dd>Sets the Miter limit for a stroked path</dd></dt>
- * <dt><code>android:state_pressed</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_focused</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_selected</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_window_focused</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_enabled</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_activated</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_accelerated</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_hovered</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_checked</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * <dt><code>android:state_checkable</code>
- * <dd>Sets a condition to be met to draw path</dd></dt>
- * </dl>
- * </dd>
- * <dt><code>&lt;animation></code></dt>
- * <dd>Used to customize the transition between two paths
- * <dl>
- * <dt><code>android:sequence</code>
- * <dd>Configures this animation sequence between the named paths.</dd></dt>
- * <dt><code>android:limitTo</code>
- * <dd>Limits an animation to only interpolate the selected variable unlimited,
- * path, rotation, trimPathStart, trimPathEnd, trimPathOffset</dd></dt>
- * <dt><code>android:repeatCount</code>
- * <dd>Number of times to loop this aspect of the animation</dd></dt>
- * <dt><code>android:durations</code>
- * <dd>The duration of each step in the animation in milliseconds Must contain
- * the number of named paths - 1</dd></dt>
- * <dt><code>android:startDelay</code>
- * <dd></dd></dt>
- * <dt><code>android:repeatStyle</code>
- * <dd>when repeating how does it repeat back and forth or a to b: forward,
- * inAndOut</dd></dt>
- * <dt><code>android:animate</code>
- * <dd>linear, accelerate, decelerate, easing</dd></dt>
  * </dl>
  * </dd>
  */
@@ -161,8 +110,6 @@
     private static final String SHAPE_VIEWPORT = "viewport";
     private static final String SHAPE_GROUP = "group";
     private static final String SHAPE_PATH = "path";
-    private static final String SHAPE_TRANSITION = "transition";
-    private static final String SHAPE_ANIMATION = "animation";
     private static final String SHAPE_VECTOR = "vector";
 
     private static final int LINECAP_BUTT = 0;
@@ -173,9 +120,6 @@
     private static final int LINEJOIN_ROUND = 1;
     private static final int LINEJOIN_BEVEL = 2;
 
-    private static final int DEFAULT_DURATION = 1000;
-    private static final long DEFAULT_INFINITE_DURATION = 60 * 60 * 1000;
-
     private final VectorDrawableState mVectorState;
 
     private int mAlpha = 0xFF;
@@ -202,7 +146,7 @@
         final int saveCount = canvas.save();
         final Rect bounds = getBounds();
         canvas.translate(bounds.left, bounds.top);
-        mVectorState.mVAnimatedPath.draw(canvas, bounds.width(), bounds.height());
+        mVectorState.mVPathRenderer.draw(canvas, bounds.width(), bounds.height());
         canvas.restoreToCount(saveCount);
     }
 
@@ -255,12 +199,12 @@
 
     @Override
     public int getIntrinsicWidth() {
-        return (int) mVectorState.mVAnimatedPath.mBaseWidth;
+        return (int) mVectorState.mVPathRenderer.mBaseWidth;
     }
 
     @Override
     public int getIntrinsicHeight() {
-        return (int) mVectorState.mVAnimatedPath.mBaseHeight;
+        return (int) mVectorState.mVPathRenderer.mBaseHeight;
     }
 
     @Override
@@ -276,8 +220,8 @@
     @Override
     public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
-        final VAnimatedPath p = inflateInternal(res, parser, attrs, theme);
-        setAnimatedPath(p);
+        final VPathRenderer p = inflateInternal(res, parser, attrs, theme);
+        setPathRenderer(p);
     }
 
     @Override
@@ -290,7 +234,7 @@
         super.applyTheme(t);
 
         final VectorDrawableState state = mVectorState;
-        final VAnimatedPath path = state.mVAnimatedPath;
+        final VPathRenderer path = state.mVPathRenderer;
         if (path != null && path.canApplyTheme()) {
             path.applyTheme(t);
         }
@@ -316,9 +260,9 @@
         return null;
     }
 
-    private VAnimatedPath inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
+    private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
             Theme theme) throws XmlPullParserException, IOException {
-        final VAnimatedPath animatedPath = new VAnimatedPath();
+        final VPathRenderer pathRenderer = new VPathRenderer();
 
         boolean noSizeTag = true;
         boolean noViewportTag = true;
@@ -336,23 +280,18 @@
                     path.inflate(res, attrs, theme);
                     currentGroup.add(path);
                     noPathTag = false;
-                } else if (SHAPE_ANIMATION.equals(tagName)) {
-                    final VAnimation anim = new VAnimation();
-                    anim.inflate(animatedPath.mGroupList, res, attrs, theme);
-                    animatedPath.addAnimation(anim);
                 } else if (SHAPE_SIZE.equals(tagName)) {
-                    animatedPath.parseSize(res, attrs);
+                    pathRenderer.parseSize(res, attrs);
                     noSizeTag = false;
                 } else if (SHAPE_VIEWPORT.equals(tagName)) {
-                    animatedPath.parseViewport(res, attrs);
+                    pathRenderer.parseViewport(res, attrs);
                     noViewportTag = false;
                 } else if (SHAPE_GROUP.equals(tagName)) {
                     currentGroup = new VGroup();
-                    animatedPath.mGroupList.add(currentGroup);
+                    pathRenderer.mGroupList.add(currentGroup);
                     noGroupTag = false;
                 } else if (SHAPE_VECTOR.equals(tagName)) {
                     final TypedArray a = res.obtainAttributes(attrs, R.styleable.VectorDrawable);
-                    animatedPath.setTrigger(a.getInteger(R.styleable.VectorDrawable_trigger, 0));
 
                     // Parsing the version information.
                     // Right now, we only support version "1".
@@ -403,23 +342,23 @@
         }
 
         // post parse cleanup
-        animatedPath.parseFinish();
-        return animatedPath;
+        pathRenderer.parseFinish();
+        return pathRenderer;
     }
 
-    private void setAnimatedPath(VAnimatedPath animatedPath) {
-        mVectorState.mVAnimatedPath = animatedPath;
+    private void setPathRenderer(VPathRenderer pathRenderer) {
+        mVectorState.mVPathRenderer = pathRenderer;
     }
 
     private static class VectorDrawableState extends ConstantState {
         int mChangingConfigurations;
-        VAnimatedPath mVAnimatedPath;
+        VPathRenderer mVPathRenderer;
         Rect mPadding;
 
         public VectorDrawableState(VectorDrawableState copy) {
             if (copy != null) {
                 mChangingConfigurations = copy.mChangingConfigurations;
-                mVAnimatedPath = new VAnimatedPath(copy.mVAnimatedPath);
+                mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
                 mPadding = new Rect(copy.mPadding);
             }
         }
@@ -445,35 +384,16 @@
         }
     }
 
-    private static class VAnimatedPath {
-        private static final int [] TRIGGER_MAP = {
-                0,
-                R.attr.state_pressed,
-                R.attr.state_focused,
-                R.attr.state_hovered,
-                R.attr.state_selected,
-                R.attr.state_checkable,
-                R.attr.state_checked,
-                R.attr.state_activated,
-                R.attr.state_focused
-        };
-
+    private static class VPathRenderer {
         private final Path mPath = new Path();
         private final Path mRenderPath = new Path();
         private final Matrix mMatrix = new Matrix();
 
-        private ArrayList<VAnimation> mCurrentAnimList;
         private VPath[] mCurrentPaths;
         private Paint mStrokePaint;
         private Paint mFillPaint;
         private PathMeasure mPathMeasure;
 
-        private int[] mCurrentState = new int[0];
-        private float mAnimationValue;
-        private long mTotalDuration;
-        private int mTrigger;
-        private boolean mTriggerState;
-
         final ArrayList<VGroup> mGroupList = new ArrayList<VGroup>();
 
         float mBaseWidth = 1;
@@ -481,11 +401,10 @@
         float mViewportWidth;
         float mViewportHeight;
 
-        public VAnimatedPath() {
+        public VPathRenderer() {
         }
 
-        public VAnimatedPath(VAnimatedPath copy) {
-            mCurrentAnimList = new ArrayList<VAnimation>(copy.mCurrentAnimList);
+        public VPathRenderer(VPathRenderer copy) {
             mGroupList.addAll(copy.mGroupList);
             if (copy.mCurrentPaths != null) {
                 mCurrentPaths = new VPath[copy.mCurrentPaths.length];
@@ -493,15 +412,11 @@
                     mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]);
                 }
             }
-            mAnimationValue = copy.mAnimationValue; // time goes from 0 to 1
 
             mBaseWidth = copy.mBaseWidth;
             mBaseHeight = copy.mBaseHeight;
             mViewportWidth = copy.mViewportHeight;
             mViewportHeight = copy.mViewportHeight;
-            mTotalDuration = copy.mTotalDuration;
-            mTrigger = copy.mTrigger;
-            mCurrentState = new int[0];
         }
 
         public boolean canApplyTheme() {
@@ -516,14 +431,6 @@
                 }
             }
 
-            final ArrayList<VAnimation> anims = mCurrentAnimList;
-            for (int i = anims.size() - 1; i >= 0; i--) {
-                final VAnimation anim = anims.get(i);
-                if (anim.canApplyTheme()) {
-                    return true;
-                }
-            }
-
             return false;
         }
 
@@ -539,70 +446,6 @@
                 }
             }
 
-            final ArrayList<VAnimation> anims = mCurrentAnimList;
-            for (int i = anims.size() - 1; i >= 0; i--) {
-                final VAnimation anim = anims.get(i);
-                if (anim.canApplyTheme()) {
-                    anim.applyTheme(t);
-                }
-            }
-        }
-
-        public void setTrigger(int trigger){
-            mTrigger = VAnimatedPath.getStateForTrigger(trigger);
-        }
-
-        public long getTotalAnimationDuration() {
-            mTotalDuration = 0;
-            int size = mCurrentAnimList.size();
-            for (int i = 0; i < size; i++) {
-                VAnimation vAnimation = mCurrentAnimList.get(i);
-                long t = vAnimation.getTotalDuration();
-                if (t == -1) {
-                    mTotalDuration = -1;
-                    return -1;
-                }
-                mTotalDuration = Math.max(mTotalDuration, t);
-            }
-
-            return mTotalDuration;
-        }
-
-        public float getValue() {
-            return mAnimationValue;
-        }
-
-        /**
-         * @param value the point along the animations to show typically between 0.0f and 1.0f
-         * @return true if you need to keep repeating
-         */
-        public boolean setAnimationFraction(float value) {
-            getTotalAnimationDuration();
-
-            long animationTime = (long) (value * mTotalDuration);
-
-            final int len = mCurrentPaths.length;
-            for (int i = 0; i < len; i++) {
-                animationTime =
-                        (long) ((mTotalDuration == -1) ? value * 1000 : mTotalDuration * value);
-
-                final VPath path = mCurrentPaths[i];
-                final int size = mCurrentAnimList.size();
-                for (int j = 0; j < size; j++) {
-                    final VAnimation vAnimation = mCurrentAnimList.get(j);
-                    if (vAnimation.doesAdjustPath(path)) {
-                        mCurrentPaths[i] =  vAnimation.getPathAtTime(animationTime, path);
-                    }
-                }
-            }
-
-            mAnimationValue = value;
-
-            if (mTotalDuration == -1) {
-                return true;
-            } else {
-                return animationTime < mTotalDuration;
-            }
         }
 
         public void draw(Canvas canvas, int w, int h) {
@@ -612,7 +455,7 @@
             }
 
             for (int i = 0; i < mCurrentPaths.length; i++) {
-                if (mCurrentPaths[i] != null && mCurrentPaths[i].isVisible(mCurrentState)) {
+                if (mCurrentPaths[i] != null) {
                     drawPath(mCurrentPaths[i], canvas, w, h);
                 }
             }
@@ -694,34 +537,10 @@
         }
 
         /**
-         * Ensure there is at least one animation for every path in group (linking them by names)
          * Build the "current" path based on the first group
          * TODO: improve memory use & performance or move to C++
          */
         public void parseFinish() {
-            final HashMap<String, VAnimation> newAnimations = new HashMap<String, VAnimation>();
-            for (VGroup group : mGroupList) {
-                for (VPath vPath : group.getPaths()) {
-                    if (!vPath.mAnimated) {
-                        VAnimation ap = null;
-
-                        if (!newAnimations.containsKey(vPath.getID())) {
-                            newAnimations.put(vPath.getID(), ap = new VAnimation());
-                        } else {
-                            ap = newAnimations.get(vPath.getID());
-                        }
-
-                        ap.addPath(vPath);
-                        vPath.mAnimated = true;
-                    }
-                }
-            }
-
-            if (mCurrentAnimList == null) {
-                mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
-            }
-            mCurrentAnimList.addAll(newAnimations.values());
-
             final Collection<VPath> paths = mGroupList.get(0).getPaths();
             mCurrentPaths = paths.toArray(new VPath[paths.size()]);
             for (int i = 0; i < mCurrentPaths.length; i++) {
@@ -729,34 +548,6 @@
             }
         }
 
-        public void setState(int[] state) {
-            mCurrentState = Arrays.copyOf(state, state.length);
-        }
-
-        int getTrigger(int []state){
-            if (mTrigger == 0) return 0;
-            for (int i = 0; i < state.length; i++) {
-                if (state[i] == mTrigger){
-                    if (mTriggerState)
-                        return 0;
-                    mTriggerState = true;
-                    return 1;
-                }
-            }
-            if (mTriggerState) {
-                mTriggerState = false;
-                return -1;
-            }
-            return 0;
-        }
-
-        public void addAnimation(VAnimation anim) {
-            if (mCurrentAnimList == null) {
-                mCurrentAnimList = new ArrayList<VectorDrawable.VAnimation>();
-            }
-            mCurrentAnimList.add(anim);
-        }
-
         private void parseViewport(Resources r, AttributeSet attrs)
                 throws XmlPullParserException {
             final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableViewport);
@@ -781,329 +572,6 @@
             a.recycle();
         }
 
-        private static final int getStateForTrigger(int trigger) {
-            return TRIGGER_MAP[trigger];
-        }
-    }
-
-    private static class VAnimation {
-        private static final String SEPARATOR = ",";
-
-        private static final int DIRECTION_FORWARD = 0;
-        private static final int DIRECTION_IN_AND_OUT = 1;
-
-        public enum Style {
-            INTERPOLATE, CROSSFADE, WIPE
-        }
-
-        private final HashSet<String> mSeqMap = new HashSet<String>();
-
-        private Interpolator mAnimInterpolator = new AccelerateDecelerateInterpolator();
-        private VPath[] mPaths = new VPath[0];
-        private long[] mDuration = { DEFAULT_DURATION };
-
-        private int[] mThemeAttrs;
-        private Style mStyle;
-        private int mLimitProperty = 0;
-        private long mStartOffset;
-        private long mRepeat = 1;
-        private long mWipeDirection;
-        private int mMode = DIRECTION_FORWARD;
-        private int mInterpolatorType;
-        private String mId;
-
-        public VAnimation() {
-            // Empty constructor.
-        }
-
-        public void inflate(ArrayList<VGroup> groups, Resources r, AttributeSet attrs, Theme theme)
-                throws XmlPullParserException {
-            String value;
-            String[] sp;
-            int name;
-
-            final TypedArray a = r.obtainAttributes(attrs, R.styleable.VectorDrawableAnimation);
-            final int[] themeAttrs = a.extractThemeAttrs();
-            mThemeAttrs = themeAttrs;
-
-            value = a.getString(R.styleable.VectorDrawableAnimation_sequence);
-            if (value != null) {
-                sp = value.split(SEPARATOR);
-                final VectorDrawable.VPath[] paths = new VectorDrawable.VPath[sp.length];
-
-                for (int j = 0; j < sp.length; j++) {
-                    mSeqMap.add(sp[j].trim());
-
-                    final VectorDrawable.VPath path = groups.get(j).get(sp[j]);
-                    if (path == null) {
-                        throw new XmlPullParserException(a.getPositionDescription()
-                                + " missing path with name: " + sp[j]);
-                    }
-
-                    path.mAnimated = true;
-                    paths[j] = path;
-                }
-
-                setPaths(paths);
-            }
-
-            name = R.styleable.VectorDrawableAnimation_durations;
-            value = a.getString(name);
-            if (value != null) {
-                long totalDuration = 0;
-                sp = value.split(SEPARATOR);
-
-                final long[] dur = new long[sp.length];
-                for (int j = 0; j < dur.length; j++) {
-                    dur[j] = Long.parseLong(sp[j]);
-                    totalDuration +=  dur[j];
-                }
-
-                if (totalDuration == 0){
-                    throw new XmlPullParserException(a.getPositionDescription()
-                            + " total duration must not be zero");
-                }
-
-                setDuration(dur);
-            }
-
-            setLimitProperty(a.getInt(R.styleable.VectorDrawableAnimation_limitTo, 0));
-            setRepeat(a.getInt(R.styleable.VectorDrawableAnimation_repeatCount, 1));
-            setStartOffset(a.getInt(R.styleable.VectorDrawableAnimation_startDelay, 0));
-            setMode(a.getInt(R.styleable.VectorDrawableAnimation_repeatStyle, 0));
-
-            fixMissingParameters();
-
-            a.recycle();
-        }
-
-        public boolean canApplyTheme() {
-            return mThemeAttrs != null;
-        }
-
-        public void applyTheme(Theme t) {
-            // TODO: Apply theme.
-        }
-
-        public boolean doesAdjustPath(VPath path) {
-            return mSeqMap.contains(path.getID());
-        }
-
-        public String getId() {
-            if (mId == null) {
-                mId = mPaths[0].getID();
-                for (int i = 1; i < mPaths.length; i++) {
-                    mId += mPaths[i].getID();
-                }
-            }
-            return mId;
-        }
-
-        public String getPathName() {
-            return mPaths[0].getID();
-        }
-
-        public Style getStyle() {
-            return mStyle;
-        }
-
-        public void setStyle(Style style) {
-            mStyle = style;
-        }
-
-        public int getLimitProperty() {
-            return mLimitProperty;
-        }
-
-        public void setLimitProperty(int limitProperty) {
-            mLimitProperty = limitProperty;
-        }
-
-        public long[] getDuration() {
-            return mDuration;
-        }
-
-        public void setDuration(long[] duration) {
-            mDuration = duration;
-        }
-
-        public long getRepeat() {
-            return mRepeat;
-        }
-
-        public void setRepeat(long repeat) {
-            mRepeat = repeat;
-        }
-
-        public long getStartOffset() {
-            return mStartOffset;
-        }
-
-        public void setStartOffset(long startOffset) {
-            mStartOffset = startOffset;
-        }
-
-        public long getWipeDirection() {
-            return mWipeDirection;
-        }
-
-        public void setWipeDirection(long wipeDirection) {
-            mWipeDirection = wipeDirection;
-        }
-
-        public int getMode() {
-            return mMode;
-        }
-
-        public void setMode(int mode) {
-            mMode = mode;
-        }
-
-        public int getInterpolator() {
-            return mInterpolatorType;
-        }
-
-        public void setInterpolator(int interpolator) {
-            mInterpolatorType = interpolator;
-        }
-
-        /**
-         * compute the total time in milliseconds
-         *
-         * @return the total time in milliseconds the animation will take
-         */
-        public long getTotalDuration() {
-            long total = mStartOffset;
-            if (getRepeat() == -1) {
-                return -1;
-            }
-            for (int i = 0; i < mDuration.length; i++) {
-                if (mRepeat > 1) {
-                    total += mDuration[i] * mRepeat;
-                } else {
-                    total += mDuration[i];
-                }
-            }
-            return total;
-        }
-
-        public void setPaths(VPath[] paths) {
-            mPaths = paths;
-        }
-
-        public void addPath(VPath path) {
-            mPaths = Arrays.copyOf(mPaths, mPaths.length + 1);
-            mPaths[mPaths.length - 1] = path;
-        }
-
-        public boolean containsPath(String pathid) {
-            for (int i = 0; i < mPaths.length; i++) {
-                if (mPaths[i].getID().equals(pathid)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public void interpolate(VPath p1, VPath p2, float time, VPath dest) {
-            VPath.interpolate(time, p1, p2, dest, mLimitProperty);
-        }
-
-        public VPath getPathAtTime(long milliseconds, VPath dest) {
-            if (mPaths.length == 1) {
-                dest.copyFrom(mPaths[0]);
-                return dest;
-            }
-            long point = milliseconds - mStartOffset;
-            if (point < 0) {
-                point = 0;
-            }
-            float time = 0;
-            long sum = mDuration[0];
-            for (int i = 1; i < mDuration.length; i++) {
-                sum += mDuration[i];
-            }
-
-            if (mRepeat > 1) {
-                time = point / (float) (sum * mRepeat);
-                time = mAnimInterpolator.getInterpolation(time);
-
-                if (mMode == DIRECTION_IN_AND_OUT) {
-                    point = ((long) (time * sum * 2 * mRepeat)) % (sum * 2);
-                    if (point > sum) {
-                        point = sum * 2 - point;
-                    }
-                } else {
-                    point = ((long) (time * sum * mRepeat)) % sum;
-                }
-            } else if (mRepeat == 1) {
-                time = point / (float) (sum * mRepeat);
-                time = mAnimInterpolator.getInterpolation(time);
-                if (mMode == DIRECTION_IN_AND_OUT) {
-                    point = ((long) (time * sum * 2 * mRepeat));
-                    if (point > sum) {
-                        point = sum * 2 - point;
-                    }
-                } else {
-                    point = Math.min(((long) (time * sum * mRepeat)), sum);
-                }
-
-            } else { // repeat = -1
-                if (mMode == DIRECTION_IN_AND_OUT) {
-                    point = point % (sum * 2);
-                    if (point > sum) {
-                        point = sum * 2 - point;
-                    }
-                    time = point / (float) sum;
-                } else {
-                    point = point % sum;
-                    time = point / (float) sum;
-                }
-            }
-
-            int transition = 0;
-            while (point > mDuration[transition]) {
-                point -= mDuration[transition++];
-            }
-            if (mPaths.length > (transition + 1)) {
-                if (mPaths[transition].getID() != dest.getID()) {
-                    dest.copyFrom(mPaths[transition]);
-                }
-                interpolate(mPaths[transition], mPaths[transition + 1],
-                        point / (float) mDuration[transition], dest);
-            } else {
-                interpolate(mPaths[transition], mPaths[transition], 0, dest);
-            }
-            return dest;
-        }
-
-        void fixMissingParameters() {
-            // fix missing points
-            float rotation = Float.NaN;
-            float rotationY = Float.NaN;
-            float rotationX = Float.NaN;
-            for (int i = 0; i < mPaths.length; i++) {
-                if (mPaths[i].mPivotX > 0) {
-                    rotationX = mPaths[i].mPivotX;
-                }
-                if (mPaths[i].mPivotY > 0) {
-                    rotationY = mPaths[i].mPivotY;
-                }
-                if (mPaths[i].mRotate > 0) {
-                    rotation = mPaths[i].mRotate;
-                }
-            }
-            if (rotation > 0) {
-                for (int i = 0; i < mPaths.length; i++) {
-                    if (mPaths[i].mPivotX == 0) {
-                        mPaths[i].mPivotX = rotationX;
-                    }
-                    if (mPaths[i].mPivotY == 0) {
-                        mPaths[i].mPivotY = rotationY;
-                    }
-                }
-            }
-        }
     }
 
     private static class VGroup {
@@ -1116,10 +584,6 @@
             mVGList.add(path);
          }
 
-        public VPath get(String name) {
-            return mVGPathMap.get(name);
-        }
-
         /**
          * Must return in order of adding
          * @return ordered list of paths
@@ -1128,23 +592,9 @@
             return mVGList;
         }
 
-        public int size() {
-            return mVGPathMap.size();
-        }
     }
 
     private static class VPath {
-        private static final int LIMIT_ALL = 0;
-        private static final int LIMIT_PATH = 1;
-        private static final int LIMIT_ROTATE = 2;
-        private static final int LIMIT_TRIM_PATH_START = 3;
-        private static final int LIMIT_TRIM_PATH_OFFSET = 5;
-        private static final int LIMIT_TRIM_PATH_END = 4;
-
-        private static final int STATE_UNDEFINED=0;
-        private static final int STATE_TRUE=1;
-        private static final int STATE_FALSE=2;
-
         private static final int MAX_STATES = 10;
 
         private int[] mThemeAttrs;
@@ -1165,7 +615,6 @@
         float mTrimPathEnd = 1;
         float mTrimPathOffset = 0;
 
-        boolean mAnimated = false;
         boolean mClip = false;
         Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
         Paint.Join mStrokeLineJoin = Paint.Join.MITER;
@@ -1176,7 +625,6 @@
         private int[] mCheckState = new int[MAX_STATES];
         private boolean[] mCheckValue = new boolean[MAX_STATES];
         private int mNumberOfStates = 0;
-        private int mNumberOfTrue = 0;
 
         public VPath() {
             // Empty constructor.
@@ -1186,38 +634,6 @@
             copyFrom(p);
         }
 
-        public void addStateFilter(int state, boolean condition) {
-            int k = 0;
-            while (k < mNumberOfStates) {
-                if (mCheckState[mNumberOfStates] == state)
-                    break;
-                k++;
-            }
-            mCheckState[k] = state;
-            mCheckValue[k] = condition;
-            if (k==mNumberOfStates){
-                mNumberOfStates++;
-            }
-            if (condition) {
-                mNumberOfTrue++;
-            }
-        }
-
-        private int getState(int state){
-            for (int i = 0; i < mNumberOfStates; i++) {
-                if (mCheckState[mNumberOfStates] == state){
-                    return (mCheckValue[i])?STATE_TRUE:STATE_FALSE;
-                }
-            }
-            return STATE_UNDEFINED;
-        }
-        /**
-         * @return the name of the path
-         */
-        public String getName() {
-            return mId;
-        }
-
         public void toPath(Path path) {
             path.reset();
             if (mNode != null) {
@@ -1342,27 +758,6 @@
                         R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
             }
 
-            // TODO: Consider replacing this with existing state attributes.
-            final int[] states = {
-                    R.styleable.VectorDrawablePath_state_activated,
-                    R.styleable.VectorDrawablePath_state_checkable,
-                    R.styleable.VectorDrawablePath_state_checked,
-                    R.styleable.VectorDrawablePath_state_enabled,
-                    R.styleable.VectorDrawablePath_state_focused,
-                    R.styleable.VectorDrawablePath_state_hovered,
-                    R.styleable.VectorDrawablePath_state_pressed,
-                    R.styleable.VectorDrawablePath_state_selected,
-                    R.styleable.VectorDrawablePath_state_window_focused
-            };
-
-            final int N = states.length;
-            for (int i = 0; i < N; i++) {
-                final int state = states[i];
-                if (a.hasValue(state)) {
-                    addStateFilter(state, a.getBoolean(state, false));
-                }
-            }
-
             updateColorAlphas();
 
             a.recycle();
@@ -1530,7 +925,6 @@
             mRotate = p1.mRotate;
             mPivotX = p1.mPivotX;
             mPivotY = p1.mPivotY;
-            mAnimated = p1.mAnimated;
             mTrimPathStart = p1.mTrimPathStart;
             mTrimPathEnd = p1.mTrimPathEnd;
             mTrimPathOffset = p1.mTrimPathOffset;
@@ -1545,118 +939,6 @@
 
             mFillRule = p1.mFillRule;
         }
-
-        public static VPath interpolate(float t, VPath p1, VPath p2, VPath returnPath, int limit) {
-            if (limit == LIMIT_ALL || limit == LIMIT_PATH) {
-                if (returnPath.mNode == null || returnPath.mNode.length != p1.mNode.length) {
-                    returnPath.mNode = new VNode[p1.mNode.length];
-                }
-                for (int i = 0; i < returnPath.mNode.length; i++) {
-                    if (returnPath.mNode[i] == null) {
-                        returnPath.mNode[i] = new VNode(p1.mNode[i], p2.mNode[i], t);
-                    } else {
-                        returnPath.mNode[i].interpolate(p1.mNode[i], p2.mNode[i], t);
-                    }
-                }
-            }
-            float t1 = 1 - t;
-            switch (limit) {
-                case LIMIT_ALL:
-                    returnPath.mRotate = t1 * p1.mRotate + t * p2.mRotate;
-                    returnPath.mPivotX = t1 * p1.mPivotX + t * p2.mPivotX;
-                    returnPath.mPivotY = t1 * p1.mPivotY + t * p2.mPivotY;
-                    returnPath.mClip = p1.mClip | p2.mClip;
-
-                    returnPath.mTrimPathStart = t1 * p1.mTrimPathStart + t * p2.mTrimPathStart;
-                    returnPath.mTrimPathEnd = t1 * p1.mTrimPathEnd + t * p2.mTrimPathEnd;
-                    returnPath.mTrimPathOffset = t1 * p1.mTrimPathOffset + t * p2.mTrimPathOffset;
-                    returnPath.mStrokeMiterlimit =
-                            t1 * p1.mStrokeMiterlimit + t * p2.mStrokeMiterlimit;
-                    returnPath.mStrokeLineCap = p1.mStrokeLineCap;
-                    if (returnPath.mStrokeLineCap == null) {
-                        returnPath.mStrokeLineCap = p2.mStrokeLineCap;
-                    }
-                    returnPath.mStrokeLineJoin = p1.mStrokeLineJoin;
-                    if (returnPath.mStrokeLineJoin == null) {
-                        returnPath.mStrokeLineJoin = p2.mStrokeLineJoin;
-                    }
-                    returnPath.mFillRule = p1.mFillRule;
-
-                    returnPath.mStrokeColor = rgbInterpolate(t, p1.mStrokeColor, p2.mStrokeColor);
-                    returnPath.mFillColor = rgbInterpolate(t, p1.mFillColor, p2.mFillColor);
-                    returnPath.mStrokeWidth = t1 * p1.mStrokeWidth + t * p2.mStrokeWidth;
-                    returnPath.mNumberOfStates = p1.mNumberOfStates;
-                    for (int i = 0; i < returnPath.mNumberOfStates; i++) {
-                        returnPath.mCheckState[i] = p1.mCheckState[i];
-                        returnPath.mCheckValue[i] = p1.mCheckValue[i];
-                    }
-                    for (int i = 0; i < p2.mNumberOfStates; i++) {
-                        returnPath.addStateFilter(p2.mCheckState[i], p2.mCheckValue[i]);
-                    }
-
-                    int count = 0;
-                    for (int i = 0; i < returnPath.mNumberOfStates; i++) {
-                        if (returnPath.mCheckValue[i]) {
-                            count++;
-                        }
-                    }
-                    returnPath.mNumberOfTrue = count;
-                    break;
-                case LIMIT_ROTATE:
-                    returnPath.mRotate = t1 * p1.mRotate + t * p2.mRotate;
-                    break;
-                case LIMIT_TRIM_PATH_END:
-                    returnPath.mTrimPathEnd = t1 * p1.mTrimPathEnd + t * p2.mTrimPathEnd;
-                    break;
-                case LIMIT_TRIM_PATH_OFFSET:
-                    returnPath.mTrimPathOffset = t1 * p1.mTrimPathOffset + t * p2.mTrimPathOffset;
-                    break;
-                case LIMIT_TRIM_PATH_START:
-                    returnPath.mTrimPathStart = t1 * p1.mTrimPathStart + t * p2.mTrimPathStart;
-                    break;
-            }
-            return returnPath;
-        }
-
-        private static int rgbInterpolate(float fraction, int startColor, int endColor) {
-            if (startColor == endColor) {
-                return startColor;
-            } else if (startColor == 0) {
-                return endColor;
-            } else if (endColor == 0) {
-                return startColor;
-            }
-
-            final int startA = (startColor >> 24) & 0xff;
-            final int startR = (startColor >> 16) & 0xff;
-            final int startG = (startColor >> 8) & 0xff;
-            final int startB = startColor & 0xff;
-
-            final int endA = (endColor >> 24) & 0xff;
-            final int endR = (endColor >> 16) & 0xff;
-            final int endG = (endColor >> 8) & 0xff;
-            final int endB = endColor & 0xff;
-
-            return ((startA + (int)(fraction * (endA - startA))) << 24) |
-                    ((startR + (int)(fraction * (endR - startR))) << 16) |
-                    ((startG + (int)(fraction * (endG - startG))) << 8) |
-                    ((startB + (int)(fraction * (endB - startB))));
-        }
-
-        public boolean isVisible(int[] state) {
-            int match = 0;
-            for (int i = 0; i < state.length; i++) {
-                int v = getState(state[i]);
-                if (v != STATE_UNDEFINED) {
-                    if (v==STATE_TRUE) {
-                        match++;
-                    } else {
-                        return false;
-                    }
-                }
-            }
-            return match == mNumberOfTrue;
-        }
     }
 
     private static class VNode {
@@ -1673,25 +955,6 @@
             mParams = Arrays.copyOf(n.mParams, n.mParams.length);
         }
 
-        public VNode(VNode n1, VNode n2, float t) {
-            mType = n1.mType;
-            mParams = new float[n1.mParams.length];
-            interpolate(n1, n2, t);
-        }
-
-        private boolean match(VNode n) {
-            if (n.mType != mType) {
-                return false;
-            }
-            return (mParams.length == n.mParams.length);
-        }
-
-        public void interpolate(VNode n1, VNode n2, float t) {
-            for (int i = 0; i < n1.mParams.length; i++) {
-                mParams[i] = n1.mParams[i] * (1 - t) + n2.mParams[i] * t;
-            }
-        }
-
         public static void createPath(VNode[] node, Path path) {
             float[] current = new float[4];
             char previousCommand = 'm';
@@ -1747,7 +1010,6 @@
                     break;
             }
             for (int k = 0; k < val.length; k += incr) {
-                // TODO: build test to prove all permutations work
                 switch (cmd) {
                     case 'm': // moveto - Start a new sub-path (relative)
                         path.rMoveTo(val[k + 0], val[k + 1]);
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index eb0cac8..2cadf09 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -6,6 +6,7 @@
 ifeq ($(USE_OPENGL_RENDERER),true)
 	LOCAL_SRC_FILES := \
 		utils/Blur.cpp \
+		utils/GLUtils.cpp \
 		utils/SortedListImpl.cpp \
 		thread/TaskManager.cpp \
 		font/CacheTexture.cpp \
@@ -53,7 +54,7 @@
 		TextureCache.cpp \
 		TextDropShadowCache.cpp
 
-	# RenderThread stuff
+# RenderThread stuff
 	LOCAL_SRC_FILES += \
 		renderthread/CanvasContext.cpp \
 		renderthread/DrawFrameTask.cpp \
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 0b074cc..86fc7c3 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -17,13 +17,13 @@
 #define ANIMATOR_H
 
 #include <cutils/compiler.h>
+#include <utils/RefBase.h>
 #include <utils/StrongPointer.h>
 
 #include "CanvasProperty.h"
 #include "Interpolator.h"
 #include "TreeInfo.h"
 #include "utils/Macros.h"
-#include "utils/VirtualLightRefBase.h"
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/CanvasProperty.h b/libs/hwui/CanvasProperty.h
index 2e1d176..6074394 100644
--- a/libs/hwui/CanvasProperty.h
+++ b/libs/hwui/CanvasProperty.h
@@ -16,8 +16,9 @@
 #ifndef CANVASPROPERTY_H
 #define CANVASPROPERTY_H
 
+#include <utils/RefBase.h>
+
 #include "utils/Macros.h"
-#include "utils/VirtualLightRefBase.h"
 
 #include <SkPaint.h>
 
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 3d58964..45b6624 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -190,7 +190,7 @@
 
         // Overlapping other operations is only allowed for text without shadow. For other ops,
         // multiDraw isn't guaranteed to overdraw correctly
-        if (!isTextBatch || state->mDrawModifiers.mHasShadow) {
+        if (!isTextBatch || op->hasTextShadow()) {
             if (intersects(state->mBounds)) return false;
         }
         const DeferredDisplayState* lhs = state;
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index eaeb772..b2ead5b 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -41,7 +41,6 @@
 #include "Matrix.h"
 #include "DeferredDisplayList.h"
 #include "RenderProperties.h"
-#include "utils/VirtualLightRefBase.h"
 
 class SkBitmap;
 class SkPaint;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index ce92beb..f1d70eb 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -183,6 +183,10 @@
         return OpenGLRenderer::getAlphaDirect(mPaint);
     }
 
+    virtual bool hasTextShadow() const {
+        return false;
+    }
+
     inline float strokeWidthOutset() {
         // since anything AA stroke with less than 1.0 pixel width is drawn with an alpha-reduced
         // 1.0 stroke, treat 1.0 as minimum.
@@ -244,11 +248,11 @@
 
     bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
         localBounds.set(mLocalBounds);
-        if (drawModifiers.mHasShadow) {
-            // TODO: inspect paint's looper directly
+        OpenGLRenderer::TextShadow textShadow;
+        if (OpenGLRenderer::getTextShadow(mPaint, &textShadow)) {
             Rect shadow(mLocalBounds);
-            shadow.translate(drawModifiers.mShadowDx, drawModifiers.mShadowDy);
-            shadow.outset(drawModifiers.mShadowRadius);
+            shadow.translate(textShadow.dx, textShadow.dx);
+            shadow.outset(textShadow.radius);
             localBounds.unionWith(shadow);
         }
         return true;
@@ -619,41 +623,6 @@
     SkiaShader* mShader;
 };
 
-class ResetShadowOp : public StateOp {
-public:
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
-        renderer.resetShadow();
-    }
-
-    virtual void output(int level, uint32_t logFlags) const {
-        OP_LOGS("ResetShadow");
-    }
-
-    virtual const char* name() { return "ResetShadow"; }
-};
-
-class SetupShadowOp : public StateOp {
-public:
-    SetupShadowOp(float radius, float dx, float dy, int color)
-            : mRadius(radius), mDx(dx), mDy(dy), mColor(color) {}
-
-    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
-        renderer.setupShadow(mRadius, mDx, mDy, mColor);
-    }
-
-    virtual void output(int level, uint32_t logFlags) const {
-        OP_LOG("SetupShadow, radius %f, %f, %f, color %#x", mRadius, mDx, mDy, mColor);
-    }
-
-    virtual const char* name() { return "SetupShadow"; }
-
-private:
-    float mRadius;
-    float mDx;
-    float mDy;
-    int mColor;
-};
-
 class ResetPaintFilterOp : public StateOp {
 public:
     virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
@@ -1351,6 +1320,10 @@
         OP_LOG("Draw some text, %d bytes", mBytesCount);
     }
 
+    virtual bool hasTextShadow() const {
+        return OpenGLRenderer::hasTextShadow(mPaint);
+    }
+
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
             const DeferredDisplayState& state) {
         const SkPaint* paint = getPaint(renderer);
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 8afd106..a4bce3a 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -57,9 +57,6 @@
 }
 
 void DisplayListRenderer::setViewport(int width, int height) {
-    // TODO: DisplayListRenderer shouldn't have a projection matrix, as it should never be used
-    mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
-
     initializeViewport(width, height);
 }
 
@@ -410,16 +407,6 @@
     addStateOp(new (alloc()) SetupShaderOp(shader));
 }
 
-void DisplayListRenderer::resetShadow() {
-    addStateOp(new (alloc()) ResetShadowOp());
-    OpenGLRenderer::resetShadow();
-}
-
-void DisplayListRenderer::setupShadow(float radius, float dx, float dy, int color) {
-    addStateOp(new (alloc()) SetupShadowOp(radius, dx, dy, color));
-    OpenGLRenderer::setupShadow(radius, dx, dy, color);
-}
-
 void DisplayListRenderer::resetPaintFilter() {
     addStateOp(new (alloc()) ResetPaintFilterOp());
 }
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 25e78c1..185179a 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -102,9 +102,6 @@
     virtual void resetShader();
     virtual void setupShader(SkiaShader* shader);
 
-    virtual void resetShadow();
-    virtual void setupShadow(float radius, float dx, float dy, int color);
-
     virtual void resetPaintFilter();
     virtual void setupPaintFilter(int clearBits, int setBits);
 
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index f06106b..2268386 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -482,8 +482,8 @@
     sy = copysignf(sqrtf(len), data[mat4::kScaleY]);
 }
 
-void Matrix4::dump() const {
-    ALOGD("Matrix4[simple=%d, type=0x%x", isSimple(), getType());
+void Matrix4::dump(const char* label) const {
+    ALOGD("%s[simple=%d, type=0x%x", label ? label : "Matrix4", isSimple(), getType());
     ALOGD("  %f %f %f %f", data[kScaleX], data[kSkewX], data[8], data[kTranslateX]);
     ALOGD("  %f %f %f %f", data[kSkewY], data[kScaleY], data[9], data[kTranslateY]);
     ALOGD("  %f %f %f %f", data[2], data[6], data[kScaleZ], data[kTranslateZ]);
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 26cb05f..e33a001 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -209,7 +209,7 @@
 
     void decomposeScale(float& sx, float& sy) const;
 
-    void dump() const;
+    void dump(const char* label = NULL) const;
 
     static const Matrix4& identity();
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 95fdb04..091cdf4 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -37,6 +37,7 @@
 #include "PathTessellator.h"
 #include "Properties.h"
 #include "ShadowTessellator.h"
+#include "utils/GLUtils.h"
 #include "Vector.h"
 #include "VertexBuffer.h"
 
@@ -170,7 +171,7 @@
 }
 
 void OpenGLRenderer::initViewport(int width, int height) {
-    mViewProjMatrix.loadOrtho(0, width, height, 0, -1, 1);
+    mSnapshot->orthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
 
     initializeViewport(width, height);
 }
@@ -296,24 +297,7 @@
 
     if (!suppressErrorChecks()) {
 #if DEBUG_OPENGL
-        GLenum status = GL_NO_ERROR;
-        while ((status = glGetError()) != GL_NO_ERROR) {
-            ALOGD("GL error from OpenGLRenderer: 0x%x", status);
-            switch (status) {
-                case GL_INVALID_ENUM:
-                    ALOGE("  GL_INVALID_ENUM");
-                    break;
-                case GL_INVALID_VALUE:
-                    ALOGE("  GL_INVALID_VALUE");
-                    break;
-                case GL_INVALID_OPERATION:
-                    ALOGE("  GL_INVALID_OPERATION");
-                    break;
-                case GL_OUT_OF_MEMORY:
-                    ALOGE("  Out of memory!");
-                    break;
-            }
-        }
+        GLUtils::dumpGLErrors();
 #endif
 
 #if DEBUG_MEMORY_USAGE
@@ -379,49 +363,9 @@
     dirtyClip();
 }
 
-void OpenGLRenderer::detachFunctor(Functor* functor) {
-    mFunctors.remove(functor);
-}
-
-void OpenGLRenderer::attachFunctor(Functor* functor) {
-    mFunctors.add(functor);
-}
-
-status_t OpenGLRenderer::invokeFunctors(Rect& dirty) {
-    status_t result = DrawGlInfo::kStatusDone;
-    size_t count = mFunctors.size();
-
-    if (count > 0) {
-        interrupt();
-        SortedVector<Functor*> functors(mFunctors);
-        mFunctors.clear();
-
-        DrawGlInfo info;
-        info.clipLeft = 0;
-        info.clipTop = 0;
-        info.clipRight = 0;
-        info.clipBottom = 0;
-        info.isLayer = false;
-        info.width = 0;
-        info.height = 0;
-        memset(info.transform, 0, sizeof(float) * 16);
-
-        for (size_t i = 0; i < count; i++) {
-            Functor* f = functors.itemAt(i);
-            result |= (*f)(DrawGlInfo::kModeProcess, &info);
-        }
-        resume();
-    }
-
-    return result;
-}
-
 status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
     if (currentSnapshot()->isIgnored()) return DrawGlInfo::kStatusDone;
 
-    detachFunctor(functor);
-
-
     Rect clip(*currentClipRect());
     clip.snapToPixelBoundaries();
 
@@ -677,14 +621,13 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
-    bool restoreOrtho = removed.flags & Snapshot::kFlagDirtyOrtho;
+    bool restoreViewport = removed.flags & Snapshot::kFlagIsFboLayer;
     bool restoreClip = removed.flags & Snapshot::kFlagClipSet;
     bool restoreLayer = removed.flags & Snapshot::kFlagIsLayer;
 
-    if (restoreOrtho) {
+    if (restoreViewport) {
         const Rect& r = restored.viewport;
         glViewport(r.left, r.top, r.right, r.bottom);
-        mViewProjMatrix.load(removed.orthoMatrix); // TODO: should ortho be stored in 'restored'?
     }
 
     if (restoreClip) {
@@ -903,14 +846,12 @@
     layer->setFbo(mCaches.fboCache.get());
 
     mSnapshot->region = &mSnapshot->layer->region;
-    mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer |
-            Snapshot::kFlagDirtyOrtho;
+    mSnapshot->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
     mSnapshot->fbo = layer->getFbo();
     mSnapshot->resetTransform(-bounds.left, -bounds.top, 0.0f);
     mSnapshot->resetClip(clip.left, clip.top, clip.right, clip.bottom);
     mSnapshot->viewport.set(0.0f, 0.0f, bounds.getWidth(), bounds.getHeight());
     mSnapshot->height = bounds.getHeight();
-    mSnapshot->orthoMatrix.load(mViewProjMatrix);
 
     endTiling();
     debugOverdraw(false, false);
@@ -939,9 +880,7 @@
 
     // Change the ortho projection
     glViewport(0, 0, bounds.getWidth(), bounds.getHeight());
-
-    // TODO: determine best way to support 3d drawing within HW layers
-    mViewProjMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
+    mSnapshot->orthoMatrix.loadOrtho(0.0f, bounds.getWidth(), bounds.getHeight(), 0.0f, -1.0f, 1.0f);
 
     return true;
 }
@@ -1745,18 +1684,20 @@
 
 void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
         float left, float top, float right, float bottom, bool ignoreTransform) {
-    mModelView.loadTranslate(left, top, 0.0f);
+    mModelViewMatrix.loadTranslate(left, top, 0.0f);
     if (mode == kModelViewMode_TranslateAndScale) {
-        mModelView.scale(right - left, bottom - top, 1.0f);
+        mModelViewMatrix.scale(right - left, bottom - top, 1.0f);
     }
 
     bool dirty = right - left > 0.0f && bottom - top > 0.0f;
-    if (!ignoreTransform) {
-        mCaches.currentProgram->set(mViewProjMatrix, mModelView, *currentTransform(), offset);
-        if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom, *currentTransform());
-    } else {
-        mCaches.currentProgram->set(mViewProjMatrix, mModelView, mat4::identity(), offset);
-        if (dirty && mTrackDirtyRegions) dirtyLayer(left, top, right, bottom);
+    const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
+    mCaches.currentProgram->set(mSnapshot->orthoMatrix, mModelViewMatrix, transformMatrix, offset);
+    if (dirty && mTrackDirtyRegions) {
+        if (!ignoreTransform) {
+            dirtyLayer(left, top, right, bottom, *currentTransform());
+        } else {
+            dirtyLayer(left, top, right, bottom);
+        }
     }
 }
 
@@ -1780,11 +1721,11 @@
             // compensate.
             mat4 modelViewWithoutTransform;
             modelViewWithoutTransform.loadInverse(*currentTransform());
-            modelViewWithoutTransform.multiply(mModelView);
-            mModelView.load(modelViewWithoutTransform);
+            modelViewWithoutTransform.multiply(mModelViewMatrix);
+            mModelViewMatrix.load(modelViewWithoutTransform);
         }
         mDrawModifiers.mShader->setupProgram(mCaches.currentProgram,
-                mModelView, *mSnapshot, &mTextureUnit);
+                mModelViewMatrix, *mSnapshot, &mTextureUnit);
     }
 }
 
@@ -2694,28 +2635,32 @@
         FontRenderer& fontRenderer, int alpha, float x, float y) {
     mCaches.activeTexture(0);
 
+    TextShadow textShadow;
+    if (!getTextShadow(paint, &textShadow)) {
+        LOG_ALWAYS_FATAL("failed to query shadow attributes");
+    }
+
     // NOTE: The drop shadow will not perform gamma correction
     //       if shader-based correction is enabled
     mCaches.dropShadowCache.setFontRenderer(fontRenderer);
     const ShadowTexture* shadow = mCaches.dropShadowCache.get(
-            paint, text, bytesCount, count, mDrawModifiers.mShadowRadius, positions);
+            paint, text, bytesCount, count, textShadow.radius, positions);
     // If the drop shadow exceeds the max texture size or couldn't be
     // allocated, skip drawing
     if (!shadow) return;
     const AutoTexture autoCleanup(shadow);
 
-    const float sx = x - shadow->left + mDrawModifiers.mShadowDx;
-    const float sy = y - shadow->top + mDrawModifiers.mShadowDy;
+    const float sx = x - shadow->left + textShadow.dx;
+    const float sy = y - shadow->top + textShadow.dy;
 
-    const int shadowAlpha = ((mDrawModifiers.mShadowColor >> 24) & 0xFF) * mSnapshot->alpha;
-    int shadowColor = mDrawModifiers.mShadowColor;
+    const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * mSnapshot->alpha;
     if (mDrawModifiers.mShader) {
-        shadowColor = 0xffffffff;
+        textShadow.color = SK_ColorWHITE;
     }
 
     setupDraw();
     setupDrawWithTexture(true);
-    setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha);
+    setupDrawAlpha8Color(textShadow.color, shadowAlpha < 255 ? shadowAlpha : alpha);
     setupDrawColorFilter(getColorFilter(paint));
     setupDrawShader();
     setupDrawBlending(paint, true);
@@ -2732,7 +2677,7 @@
 }
 
 bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
-    float alpha = (mDrawModifiers.mHasShadow ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
+    float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * mSnapshot->alpha;
     return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
 }
 
@@ -2764,7 +2709,7 @@
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
-    if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
+    if (CC_UNLIKELY(hasTextShadow(paint))) {
         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
                 alpha, 0.0f, 0.0f);
     }
@@ -2841,7 +2786,7 @@
 
     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
 
-    if (CC_UNLIKELY(mDrawModifiers.mHasShadow)) {
+    if (CC_UNLIKELY(hasTextShadow(paint))) {
         fontRenderer.setFont(paint, mat4::identity());
         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
                 alpha, oldX, oldY);
@@ -3062,22 +3007,6 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// Drop shadow
-///////////////////////////////////////////////////////////////////////////////
-
-void OpenGLRenderer::resetShadow() {
-    mDrawModifiers.mHasShadow = false;
-}
-
-void OpenGLRenderer::setupShadow(float radius, float dx, float dy, int color) {
-    mDrawModifiers.mHasShadow = true;
-    mDrawModifiers.mShadowRadius = radius;
-    mDrawModifiers.mShadowDx = dx;
-    mDrawModifiers.mShadowDy = dy;
-    mDrawModifiers.mShadowColor = color;
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // Draw filters
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 7794abc..d140428 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -29,6 +29,7 @@
 #include <SkShader.h>
 #include <SkXfermode.h>
 
+#include <utils/Blur.h>
 #include <utils/Functor.h>
 #include <utils/RefBase.h>
 #include <utils/SortedVector.h>
@@ -72,13 +73,6 @@
     SkiaShader* mShader;
     float mOverrideLayerAlpha;
 
-    // Drop shadow
-    bool mHasShadow;
-    float mShadowRadius;
-    float mShadowDx;
-    float mShadowDy;
-    int mShadowColor;
-
     // Draw filters
     bool mHasDrawFilter;
     int mPaintFilterClearBits;
@@ -151,9 +145,6 @@
         return mCountOverdraw ? mOverdraw : 0.0f;
     }
 
-    ANDROID_API status_t invokeFunctors(Rect& dirty);
-    ANDROID_API void detachFunctor(Functor* functor);
-    ANDROID_API void attachFunctor(Functor* functor);
     virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty);
 
     ANDROID_API void pushLayerUpdate(Layer* layer);
@@ -229,9 +220,6 @@
     virtual void resetShader();
     virtual void setupShader(SkiaShader* shader);
 
-    virtual void resetShadow();
-    virtual void setupShadow(float radius, float dx, float dy, int color);
-
     virtual void resetPaintFilter();
     virtual void setupPaintFilter(int clearBits, int setBits);
 
@@ -319,6 +307,31 @@
         return paint->getAlpha();
     }
 
+    struct TextShadow {
+        SkScalar radius;
+        float dx;
+        float dy;
+        SkColor color;
+    };
+
+    static inline bool getTextShadow(const SkPaint* paint, TextShadow* textShadow) {
+        SkDrawLooper::BlurShadowRec blur;
+        if (paint && paint->getLooper() && paint->getLooper()->asABlurShadow(&blur)) {
+            if (textShadow) {
+                textShadow->radius = Blur::convertSigmaToRadius(blur.fSigma);
+                textShadow->dx = blur.fOffset.fX;
+                textShadow->dy = blur.fOffset.fY;
+                textShadow->color = blur.fColor;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    static inline bool hasTextShadow(const SkPaint* paint) {
+        return getTextShadow(paint, NULL);
+    }
+
     /**
      * Return the best transform to use to rasterize text given a full
      * transform matrix.
@@ -917,24 +930,21 @@
      */
     Texture* getTexture(const SkBitmap* bitmap);
 
-    // Matrix used for view/projection in shaders
-    mat4 mViewProjMatrix;
-
     /**
      * Model-view matrix used to position/size objects
      *
      * Stores operation-local modifications to the draw matrix that aren't incorporated into the
      * currentTransform().
      *
-     * If generated with kModelViewMode_Translate, the mModelView will reflect an x/y offset,
+     * If generated with kModelViewMode_Translate, mModelViewMatrix will reflect an x/y offset,
      * e.g. the offset in drawLayer(). If generated with kModelViewMode_TranslateAndScale,
-     * mModelView will reflect a translation and scale, e.g. the translation and scale required to
-     * make VBO 0 (a rect of (0,0,1,1)) scaled to match the x,y offset, and width/height of a
-     * bitmap.
+     * mModelViewMatrix will reflect a translation and scale, e.g. the translation and scale
+     * required to make VBO 0 (a rect of (0,0,1,1)) scaled to match the x,y offset, and width/height
+     * of a bitmap.
      *
      * Used as input to SkiaShader transformation.
      */
-    mat4 mModelView;
+    mat4 mModelViewMatrix;
 
     // State used to define the clipping region
     Rect mTilingClip;
@@ -959,8 +969,6 @@
 
     // List of rectangles to clear after saveLayer() is invoked
     Vector<Rect*> mLayers;
-    // List of functors to invoke after a frame is drawn
-    SortedVector<Functor*> mFunctors;
     // List of layers to update at the beginning of a frame
     Vector<Layer*> mLayerUpdates;
 
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 92964a8..f38d8b7 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -175,6 +175,10 @@
         bottom += dy;
     }
 
+    void inset(float delta) {
+        outset(-delta);
+    }
+
     void outset(float delta) {
         left -= delta;
         top -= delta;
@@ -230,8 +234,8 @@
         bottom = ceilf(bottom);
     }
 
-    void dump() const {
-        ALOGD("Rect[l=%f t=%f r=%f b=%f]", left, top, right, bottom);
+    void dump(const char* label) const {
+        ALOGD("%s[l=%f t=%f r=%f b=%f]", label ? label : "Rect", left, top, right, bottom);
     }
 
 private:
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 159903c..bc62ee1 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -45,7 +45,6 @@
 #include "DisplayList.h"
 #include "RenderProperties.h"
 #include "TreeInfo.h"
-#include "utils/VirtualLightRefBase.h"
 
 class SkBitmap;
 class SkPaint;
diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h
index 3209a53..57db816 100644
--- a/libs/hwui/Renderer.h
+++ b/libs/hwui/Renderer.h
@@ -178,9 +178,6 @@
     virtual void resetShader() = 0;
     virtual void setupShader(SkiaShader* shader) = 0;
 
-    virtual void resetShadow() = 0;
-    virtual void setupShadow(float radius, float dx, float dy, int color) = 0;
-
     virtual void resetPaintFilter() = 0;
     virtual void setupPaintFilter(int clearBits, int setBits) = 0;
 
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index d26ee38..b2df86f 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -27,9 +27,15 @@
 // Constructors
 ///////////////////////////////////////////////////////////////////////////////
 
-Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0),
-        invisible(false), empty(false), alpha(1.0f) {
-
+Snapshot::Snapshot()
+        : flags(0)
+        , previous(NULL)
+        , layer(NULL)
+        , fbo(0)
+        , invisible(false)
+        , empty(false)
+        , height(0)
+        , alpha(1.0f) {
     transform = &mTransformRoot;
     clipRect = &mClipRectRoot;
     region = NULL;
@@ -40,10 +46,17 @@
  * Copies the specified snapshot/ The specified snapshot is stored as
  * the previous snapshot.
  */
-Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
-        flags(0), previous(s), layer(s->layer), fbo(s->fbo),
-        invisible(s->invisible), empty(false),
-        viewport(s->viewport), height(s->height), alpha(s->alpha) {
+Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags)
+        : flags(0)
+        , previous(s)
+        , layer(s->layer)
+        , fbo(s->fbo)
+        , invisible(s->invisible)
+        , empty(false)
+        , viewport(s->viewport)
+        , height(s->height)
+        , orthoMatrix(s->orthoMatrix)
+        , alpha(s->alpha) {
 
     if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
         mTransformRoot.load(*s->transform);
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 038aea8..aede079 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -65,17 +65,16 @@
          * Indicates that this snapshot is a special type of layer
          * backed by an FBO. This flag only makes sense when the
          * flag kFlagIsLayer is also set.
+         *
+         * Viewport has been modified to fit the new Fbo, and must be
+         * restored when this snapshot is restored.
          */
         kFlagIsFboLayer = 0x4,
         /**
-         * Indicates that this snapshot has changed the ortho matrix.
-         */
-        kFlagDirtyOrtho = 0x8,
-        /**
          * Indicates that this snapshot or an ancestor snapshot is
          * an FBO layer.
          */
-        kFlagFboTarget = 0x10
+        kFlagFboTarget = 0x8,
     };
 
     /**
@@ -183,7 +182,7 @@
     int height;
 
     /**
-     * Contains the previous ortho matrix.
+     * Contains the current orthographic, projection matrix.
      */
     mat4 orthoMatrix;
 
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index d22cb8a..08e9a1a 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -214,18 +214,28 @@
     int dstY = y + glyph->mBitmapTop;
 
     CacheTexture* cacheTexture = glyph->mCacheTexture;
-
-    uint32_t cacheWidth = cacheTexture->getWidth();
-    uint32_t startY = glyph->mStartY * cacheWidth;
-    uint32_t endY = startY + (glyph->mBitmapHeight * cacheWidth);
-
     PixelBuffer* pixelBuffer = cacheTexture->getPixelBuffer();
+
+    uint32_t formatSize = PixelBuffer::formatSize(pixelBuffer->getFormat());
+    uint32_t cacheWidth = cacheTexture->getWidth();
+    uint32_t srcStride = formatSize * cacheWidth;
+    uint32_t startY = glyph->mStartY * srcStride;
+    uint32_t endY = startY + (glyph->mBitmapHeight * srcStride);
+
     const uint8_t* cacheBuffer = pixelBuffer->map();
 
     for (uint32_t cacheY = startY, bitmapY = dstY * bitmapWidth; cacheY < endY;
-            cacheY += cacheWidth, bitmapY += bitmapWidth) {
-        memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth);
+            cacheY += srcStride, bitmapY += bitmapWidth) {
+
+        if (formatSize == 1) {
+            memcpy(&bitmap[bitmapY + dstX], &cacheBuffer[cacheY + glyph->mStartX], glyph->mBitmapWidth);
+        } else {
+            for (uint32_t i = 0; i < glyph->mBitmapWidth; ++i) {
+                bitmap[bitmapY + dstX + i] = cacheBuffer[cacheY + (glyph->mStartX + i)*formatSize];
+            }
+        }
     }
+
 }
 
 void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index fc3548c..5a23158 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -349,6 +349,8 @@
         mDirtyRegionsEnabled = mGlobalContext->enableDirtyRegions(mEglSurface);
         mHaveNewSurface = true;
         makeCurrent();
+    } else {
+        mRenderThread.removeFrameCallback(this);
     }
 }
 
@@ -385,6 +387,10 @@
     mCanvas->setViewport(width, height);
 }
 
+void CanvasContext::setOpaque(bool opaque) {
+    mOpaque = opaque;
+}
+
 void CanvasContext::makeCurrent() {
     // TODO: Figure out why this workaround is needed, see b/13913604
     // In the meantime this matches the behavior of GLRenderer, so it is not a regression
@@ -468,6 +474,10 @@
 
 // Called by choreographer to do an RT-driven animation
 void CanvasContext::doFrame() {
+    if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) {
+        return;
+    }
+
     ATRACE_CALL();
 
     TreeInfo info;
@@ -486,10 +496,7 @@
         requireGlContext();
         mode = DrawGlInfo::kModeProcess;
     }
-    // TODO: Remove the dummy info in the future
-    DrawGlInfo dummyInfo;
-    memset(&dummyInfo, 0, sizeof(DrawGlInfo));
-    (*functor)(mode, &dummyInfo);
+    (*functor)(mode, NULL);
 
     if (mCanvas) {
         mCanvas->resume();
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index a95e27a..dcb9858 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -52,6 +52,7 @@
     void updateSurface(EGLNativeWindowType window);
     void pauseSurface(EGLNativeWindowType window);
     void setup(int width, int height);
+    void setOpaque(bool opaque);
     void makeCurrent();
     void prepareDraw(const Vector<DeferredLayerUpdater*>* layerUpdaters, TreeInfo& info);
     void draw(Rect* dirty);
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index c2806fa..82a2dbc 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -159,6 +159,18 @@
     post(task);
 }
 
+CREATE_BRIDGE2(setOpaque, CanvasContext* context, bool opaque) {
+    args->context->setOpaque(args->opaque);
+    return NULL;
+}
+
+void RenderProxy::setOpaque(bool opaque) {
+    SETUP_TASK(setOpaque);
+    args->context = mContext;
+    args->opaque = opaque;
+    post(task);
+}
+
 int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos,
         int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) {
     mDrawFrameTask.setDirty(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 013c3bd..4a7e70a 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -67,6 +67,7 @@
     ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
     ANDROID_API void pauseSurface(const sp<ANativeWindow>& window);
     ANDROID_API void setup(int width, int height);
+    ANDROID_API void setOpaque(bool opaque);
     ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos,
             int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom);
     ANDROID_API void destroyCanvasAndSurface();
diff --git a/libs/hwui/utils/Blur.cpp b/libs/hwui/utils/Blur.cpp
index 85d90d0..c020b40 100644
--- a/libs/hwui/utils/Blur.cpp
+++ b/libs/hwui/utils/Blur.cpp
@@ -23,6 +23,31 @@
 namespace android {
 namespace uirenderer {
 
+// This constant approximates the scaling done in the software path's
+// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
+static const float BLUR_SIGMA_SCALE = 0.57735f;
+
+float Blur::convertRadiusToSigma(float radius) {
+    return radius > 0 ? BLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
+}
+
+float Blur::convertSigmaToRadius(float sigma) {
+    return sigma > 0.5f ? (sigma - 0.5f) / BLUR_SIGMA_SCALE : 0.0f;
+}
+
+/**
+ * HWUI has used a slightly different equation than Skia to generate the value
+ * for sigma and to preserve compatibility we have kept that logic.
+ *
+ * Based on some experimental radius and sigma values we approximate the
+ * equation sigma = f(radius) as sigma = radius * 0.3  + 0.6.  The larger the
+ * radius gets, the more our gaussian blur will resemble a box blur since with
+ * large sigma the gaussian curve begins to lose its shape.
+ */
+static float legacyConvertRadiusToSigma(float radius) {
+    return radius > 0 ? 0.3f * radius + 0.6f : 0.0f;
+}
+
 void Blur::generateGaussianWeights(float* weights, int32_t radius) {
     // Compute gaussian weights for the blur
     // e is the euler's number
@@ -31,13 +56,7 @@
     // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
     // x is of the form [-radius .. 0 .. radius]
     // and sigma varies with radius.
-    // Based on some experimental radius values and sigma's
-    // we approximately fit sigma = f(radius) as
-    // sigma = radius * 0.3  + 0.6
-    // The larger the radius gets, the more our gaussian blur
-    // will resemble a box blur since with large sigma
-    // the gaussian curve begins to lose its shape
-    float sigma = 0.3f * (float) radius + 0.6f;
+    float sigma = legacyConvertRadiusToSigma((float) radius);
 
     // Now compute the coefficints
     // We will store some redundant values to save some math during
diff --git a/libs/hwui/utils/Blur.h b/libs/hwui/utils/Blur.h
index 6c176e9..79aff65 100644
--- a/libs/hwui/utils/Blur.h
+++ b/libs/hwui/utils/Blur.h
@@ -18,12 +18,18 @@
 #define ANDROID_HWUI_BLUR_H
 
 #include <stdint.h>
+#include <cutils/compiler.h>
 
 namespace android {
 namespace uirenderer {
 
 class Blur {
 public:
+    // If radius > 0, return the corresponding sigma, else return 0
+    ANDROID_API static float convertRadiusToSigma(float radius);
+    // If sigma > 0.6, return the corresponding radius, else return 0
+    ANDROID_API static float convertSigmaToRadius(float sigma);
+
     static void generateGaussianWeights(float* weights, int32_t radius);
     static void horizontal(float* weights, int32_t radius, const uint8_t* source,
         uint8_t* dest, int32_t width, int32_t height);
diff --git a/libs/hwui/utils/GLUtils.cpp b/libs/hwui/utils/GLUtils.cpp
new file mode 100644
index 0000000..9b298ca
--- /dev/null
+++ b/libs/hwui/utils/GLUtils.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <utils/Log.h>
+
+#include "GLUtils.h"
+
+namespace android {
+namespace uirenderer {
+
+void GLUtils::dumpGLErrors() {
+    GLenum status = GL_NO_ERROR;
+    while ((status = glGetError()) != GL_NO_ERROR) {
+        switch (status) {
+        case GL_INVALID_ENUM:
+            ALOGE("GL error:  GL_INVALID_ENUM");
+            break;
+        case GL_INVALID_VALUE:
+            ALOGE("GL error:  GL_INVALID_VALUE");
+            break;
+        case GL_INVALID_OPERATION:
+            ALOGE("GL error:  GL_INVALID_OPERATION");
+            break;
+        case GL_OUT_OF_MEMORY:
+            ALOGE("GL error:  Out of memory!");
+            break;
+        default:
+            ALOGE("GL error: 0x%x", status);
+        }
+    }
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/VirtualLightRefBase.h b/libs/hwui/utils/GLUtils.h
similarity index 66%
rename from libs/hwui/utils/VirtualLightRefBase.h
rename to libs/hwui/utils/GLUtils.h
index b545aab..890e374 100644
--- a/libs/hwui/utils/VirtualLightRefBase.h
+++ b/libs/hwui/utils/GLUtils.h
@@ -13,22 +13,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#ifndef VIRTUALLIGHTREFBASE_H
-#define VIRTUALLIGHTREFBASE_H
-
-#include <utils/RefBase.h>
+#ifndef GLUTILS_H
+#define GLUTILS_H
 
 namespace android {
 namespace uirenderer {
 
-// This is a wrapper around LightRefBase that simply enforces a virtual
-// destructor to eliminate the template requirement of LightRefBase
-class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> {
+class GLUtils {
+private:
 public:
-    virtual ~VirtualLightRefBase() {}
-};
+    /**
+     * Print out any GL errors with ALOGE
+     */
+    static void dumpGLErrors();
+
+}; // class GLUtils
 
 } /* namespace uirenderer */
 } /* namespace android */
 
-#endif /* VIRTUALLIGHTREFBASE_H */
+#endif /* GLUTILS_H */
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index 7deabe9..8ba44dc 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -38,4 +38,4 @@
 } /* namespace uirenderer */
 } /* namespace android */
 
-#endif /* RENDERNODE_H */
+#endif /* MATHUTILS_H */
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 6b2a247..57274ee 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -37,7 +37,7 @@
     public static final int ENCODING_PCM_16BIT = 2;
     /** Audio data format: PCM 8 bit per sample. Not guaranteed to be supported by devices. */
     public static final int ENCODING_PCM_8BIT = 3;
-    /** @hide Candidate for public API */
+    /** Audio data format: single-precision floating-point per sample */
     public static final int ENCODING_PCM_FLOAT = 4;
 
     /** Invalid audio channel configuration */
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 0c8a823..724022b 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -149,6 +149,7 @@
     private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
     private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
     private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
+    private static final int MSG_SYSTEM_READY = 21;
     // start of messages handled under wakelock
     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
     //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -370,7 +371,7 @@
     private int mScoConnectionState;
 
     // true if boot sequence has been completed
-    private boolean mBootCompleted;
+    private boolean mSystemReady;
     // listener for SoundPool sample load completion indication
     private SoundPoolCallback mSoundPoolCallBack;
     // thread for SoundPool listener
@@ -525,7 +526,6 @@
         intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
         intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
         intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
-        intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
@@ -559,6 +559,43 @@
 
     }
 
+    public void systemReady() {
+        sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
+                0, 0, null, 0);
+    }
+
+    public void onSystemReady() {
+        mSystemReady = true;
+        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
+                0, 0, null, 0);
+
+        mKeyguardManager =
+                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+        mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
+        resetBluetoothSco();
+        getBluetoothHeadset();
+        //FIXME: this is to maintain compatibility with deprecated intent
+        // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
+        Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
+        newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
+                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+        sendStickyBroadcastToAll(newIntent);
+
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (adapter != null) {
+            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
+                                    BluetoothProfile.A2DP);
+        }
+
+        sendMsg(mAudioHandler,
+                MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
+                SENDMSG_REPLACE,
+                0,
+                0,
+                null,
+                SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
+    }
+
     private void createAudioSystemThread() {
         mAudioSystemThread = new AudioSystemThread();
         mAudioSystemThread.start();
@@ -1996,7 +2033,7 @@
     /** @see AudioManager#startBluetoothSco() */
     public void startBluetoothSco(IBinder cb, int targetSdkVersion){
         if (!checkAudioSettingsPermission("startBluetoothSco()") ||
-                !mBootCompleted) {
+                !mSystemReady) {
             return;
         }
         ScoClient client = getScoClient(cb, true);
@@ -2013,7 +2050,7 @@
     /** @see AudioManager#stopBluetoothSco() */
     public void stopBluetoothSco(IBinder cb){
         if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
-                !mBootCompleted) {
+                !mSystemReady) {
             return;
         }
         ScoClient client = getScoClient(cb, false);
@@ -3277,7 +3314,7 @@
             int status;
 
             synchronized (mSoundEffectsLock) {
-                if (!mBootCompleted) {
+                if (!mSystemReady) {
                     Log.w(TAG, "onLoadSoundEffects() called before boot complete");
                     return false;
                 }
@@ -3700,6 +3737,10 @@
                 case MSG_BROADCAST_BT_CONNECTION_STATE:
                     onBroadcastScoConnectionState(msg.arg1);
                     break;
+
+                case MSG_SYSTEM_READY:
+                    onSystemReady();
+                    break;
             }
         }
     }
@@ -4169,36 +4210,6 @@
                     newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
                     sendStickyBroadcastToAll(newIntent);
                 }
-            } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
-                mBootCompleted = true;
-                sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
-                        0, 0, null, 0);
-
-                mKeyguardManager =
-                        (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-                mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
-                resetBluetoothSco();
-                getBluetoothHeadset();
-                //FIXME: this is to maintain compatibility with deprecated intent
-                // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
-                Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
-                newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
-                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                sendStickyBroadcastToAll(newIntent);
-
-                BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-                if (adapter != null) {
-                    adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
-                                            BluetoothProfile.A2DP);
-                }
-
-                sendMsg(mAudioHandler,
-                        MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
-                        SENDMSG_REPLACE,
-                        0,
-                        0,
-                        null,
-                        SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
             } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
                 AudioSystem.setParameters("screen_state=on");
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 1899685..1a64cff 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -42,7 +42,8 @@
  * The AudioTrack class manages and plays a single audio resource for Java applications.
  * It allows streaming of PCM audio buffers to the audio sink for playback. This is
  * achieved by "pushing" the data to the AudioTrack object using one of the
- *  {@link #write(byte[], int, int)} and {@link #write(short[], int, int)} methods.
+ *  {@link #write(byte[], int, int)}, {@link #write(short[], int, int)},
+ *  and {@link #write(float[], int, int, int)} methods.
  *
  * <p>An AudioTrack instance can operate under two modes: static or streaming.<br>
  * In Streaming mode, the application writes a continuous stream of data to the AudioTrack, using
@@ -172,16 +173,14 @@
     public @interface WriteMode {}
 
     /**
-     * @hide CANDIDATE FOR PUBLIC API
      * The write mode indicating the write operation will block until all data has been written,
-     * to be used in {@link #write(ByteBuffer, int, int, int)}.
+     * to be used in {@link #write(ByteBuffer, int, int)}
      */
     public final static int WRITE_BLOCKING = 0;
     /**
-     * @hide CANDIDATE FOR PUBLIC API
      * The write mode indicating the write operation will return immediately after
      * queuing as much audio data for playback as possible without blocking, to be used in
-     * {@link #write(ByteBuffer, int, int, int)}.
+     * {@link #write(ByteBuffer, int, int)}.
      */
     public final static int WRITE_NON_BLOCKING = 1;
 
@@ -246,6 +245,7 @@
      * The encoding of the audio samples.
      * @see AudioFormat#ENCODING_PCM_8BIT
      * @see AudioFormat#ENCODING_PCM_16BIT
+     * @see AudioFormat#ENCODING_PCM_FLOAT
      */
     private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
     /**
@@ -287,8 +287,9 @@
      *   See {@link AudioFormat#CHANNEL_OUT_MONO} and
      *   {@link AudioFormat#CHANNEL_OUT_STEREO}
      * @param audioFormat the format in which the audio data is represented.
-     *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
-     *   {@link AudioFormat#ENCODING_PCM_8BIT}
+     *   See {@link AudioFormat#ENCODING_PCM_16BIT},
+     *   {@link AudioFormat#ENCODING_PCM_8BIT},
+     *   and {@link AudioFormat#ENCODING_PCM_FLOAT}.
      * @param bufferSizeInBytes the total size (in bytes) of the internal buffer where audio data is
      *   read from for playback.
      *   If track's creation mode is {@link #MODE_STREAM}, you can write data into
@@ -331,7 +332,8 @@
      *   {@link AudioFormat#CHANNEL_OUT_STEREO}
      * @param audioFormat the format in which the audio data is represented.
      *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
-     *   {@link AudioFormat#ENCODING_PCM_8BIT}
+     *   {@link AudioFormat#ENCODING_PCM_8BIT},
+     *   and {@link AudioFormat#ENCODING_PCM_FLOAT}.
      * @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is read
      *   from for playback. If using the AudioTrack in streaming mode, you can write data into
      *   this buffer in smaller chunks than this size. If using the AudioTrack in static mode,
@@ -461,11 +463,14 @@
             break;
         case AudioFormat.ENCODING_PCM_16BIT:
         case AudioFormat.ENCODING_PCM_8BIT:
+        case AudioFormat.ENCODING_PCM_FLOAT:
             mAudioFormat = audioFormat;
             break;
         default:
             throw new IllegalArgumentException("Unsupported sample encoding."
-                + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT.");
+                + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT"
+                + " or ENCODING_PCM_FLOAT"
+                + ".");
         }
 
         //--------------
@@ -725,7 +730,8 @@
      *   {@link AudioFormat#CHANNEL_OUT_STEREO}
      * @param audioFormat the format in which the audio data is represented.
      *   See {@link AudioFormat#ENCODING_PCM_16BIT} and
-     *   {@link AudioFormat#ENCODING_PCM_8BIT}
+     *   {@link AudioFormat#ENCODING_PCM_8BIT},
+     *   and {@link AudioFormat#ENCODING_PCM_FLOAT}.
      * @return {@link #ERROR_BAD_VALUE} if an invalid parameter was passed,
      *   or {@link #ERROR} if unable to query for output properties,
      *   or the minimum buffer size expressed in bytes.
@@ -752,7 +758,8 @@
         }
 
         if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT)
-            && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) {
+            && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)
+            && (audioFormat != AudioFormat.ENCODING_PCM_FLOAT)) {
             loge("getMinBufferSize(): Invalid audio format.");
             return ERROR_BAD_VALUE;
         }
@@ -1152,7 +1159,7 @@
 
     public int write(byte[] audioData, int offsetInBytes, int sizeInBytes) {
 
-        if (mState == STATE_UNINITIALIZED) {
+        if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
             return ERROR_INVALID_OPERATION;
         }
 
@@ -1190,13 +1197,13 @@
      *     starts.
      * @param sizeInShorts the number of shorts to read in audioData after the offset.
      * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION}
-      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-      *    the parameters don't resolve to valid data and indexes.
+     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+     *    the parameters don't resolve to valid data and indexes.
      */
 
     public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {
 
-        if (mState == STATE_UNINITIALIZED) {
+        if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
             return ERROR_INVALID_OPERATION;
         }
 
@@ -1220,7 +1227,79 @@
 
 
     /**
-     * @hide CANDIDATE FOR PUBLIC API
+     * Writes the audio data to the audio sink for playback (streaming mode),
+     * or copies audio data for later playback (static buffer mode).
+     * In static buffer mode, copies the data to the buffer starting at offset 0,
+     * and the write mode is ignored.
+     * In streaming mode, the blocking behavior will depend on the write mode.
+     * <p>
+     * Note that the actual playback of this data might occur after this function
+     * returns. This function is thread safe with respect to {@link #stop} calls,
+     * in which case all of the specified data might not be written to the audio sink.
+     * <p>
+     * @param audioData the array that holds the data to play.
+     *     The implementation does not clip for sample values within the nominal range
+     *     [-1.0f, 1.0f], provided that all gains in the audio pipeline are
+     *     less than or equal to unity (1.0f), and in the absence of post-processing effects
+     *     that could add energy, such as reverb.  For the convenience of applications
+     *     that compute samples using filters with non-unity gain,
+     *     sample values +3 dB beyond the nominal range are permitted.
+     *     However such values may eventually be limited or clipped, depending on various gains
+     *     and later processing in the audio path.  Therefore applications are encouraged
+     *     to provide samples values within the nominal range.
+     * @param offsetInFloats the offset, expressed as a number of floats,
+     *     in audioData where the data to play starts.
+     * @param sizeInFloats the number of floats to read in audioData after the offset.
+     * @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no
+     *     effect in static mode.
+     *     <BR>With {@link #WRITE_BLOCKING}, the write will block until all data has been written
+     *         to the audio sink.
+     *     <BR>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
+     *     queuing as much audio data for playback as possible without blocking.
+     * @return the number of floats that were written, or {@link #ERROR_INVALID_OPERATION}
+     *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
+     *    the parameters don't resolve to valid data and indexes.
+     */
+    public int write(float[] audioData, int offsetInFloats, int sizeInFloats,
+            @WriteMode int writeMode) {
+
+        if (mState == STATE_UNINITIALIZED) {
+            Log.e(TAG, "AudioTrack.write() called in invalid state STATE_UNINITIALIZED");
+            return ERROR_INVALID_OPERATION;
+        }
+
+        if (mAudioFormat != AudioFormat.ENCODING_PCM_FLOAT) {
+            Log.e(TAG, "AudioTrack.write(float[] ...) requires format ENCODING_PCM_FLOAT");
+            return ERROR_INVALID_OPERATION;
+        }
+
+        if ((writeMode != WRITE_BLOCKING) && (writeMode != WRITE_NON_BLOCKING)) {
+            Log.e(TAG, "AudioTrack.write() called with invalid blocking mode");
+            return ERROR_BAD_VALUE;
+        }
+
+        if ( (audioData == null) || (offsetInFloats < 0 ) || (sizeInFloats < 0)
+                || (offsetInFloats + sizeInFloats < 0)  // detect integer overflow
+                || (offsetInFloats + sizeInFloats > audioData.length)) {
+            Log.e(TAG, "AudioTrack.write() called with invalid array, offset, or size");
+            return ERROR_BAD_VALUE;
+        }
+
+        int ret = native_write_float(audioData, offsetInFloats, sizeInFloats, mAudioFormat,
+                writeMode == WRITE_BLOCKING);
+
+        if ((mDataLoadMode == MODE_STATIC)
+                && (mState == STATE_NO_STATIC_DATA)
+                && (ret > 0)) {
+            // benign race with respect to other APIs that read mState
+            mState = STATE_INITIALIZED;
+        }
+
+        return ret;
+    }
+
+
+    /**
      * Writes the audio data to the audio sink for playback (streaming mode),
      * or copies audio data for later playback (static buffer mode).
      * In static buffer mode, copies the data to the buffer starting at its 0 offset, and the write
@@ -1250,6 +1329,11 @@
             return ERROR_INVALID_OPERATION;
         }
 
+        if (mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
+            Log.e(TAG, "AudioTrack.write(ByteBuffer ...) not yet supported for ENCODING_PCM_FLOAT");
+            return ERROR_INVALID_OPERATION;
+        }
+
         if ((writeMode != WRITE_BLOCKING) && (writeMode != WRITE_NON_BLOCKING)) {
             Log.e(TAG, "AudioTrack.write() called with invalid blocking mode");
             return ERROR_BAD_VALUE;
@@ -1490,6 +1574,10 @@
     private native final int native_write_short(short[] audioData,
                                                 int offsetInShorts, int sizeInShorts, int format);
 
+    private native final int native_write_float(float[] audioData,
+                                                int offsetInFloats, int sizeInFloats, int format,
+                                                boolean isBlocking);
+
     private native final int native_write_native_bytes(Object audioData,
             int positionInBytes, int sizeInBytes, int format, boolean blocking);
 
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 115786c..34c55202 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -585,11 +585,63 @@
      * the codec. If you previously specified a surface when configuring this
      * video decoder you can optionally render the buffer.
      * @param index The index of a client-owned output buffer previously returned
-     *              in a call to {@link #dequeueOutputBuffer}.
+     *              from a call to {@link #dequeueOutputBuffer}.
      * @param render If a valid surface was specified when configuring the codec,
      *               passing true renders this output buffer to the surface.
      */
-    public native final void releaseOutputBuffer(int index, boolean render);
+    public final void releaseOutputBuffer(int index, boolean render) {
+        releaseOutputBuffer(index, render, false /* updatePTS */, 0 /* dummy */);
+    }
+
+    /**
+     * If you are done with a buffer, use this call to update its surface timestamp
+     * and return it to the codec to render it on the output surface. If you
+     * have not specified an output surface when configuring this video codec,
+     * this call will simply return the buffer to the codec.<p>
+     *
+     * The timestamp may have special meaning depending on the destination surface.
+     *
+     * <table>
+     * <tr><th>SurfaceView specifics</th></tr>
+     * <tr><td>
+     * If you render your buffer on a {@link android.view.SurfaceView},
+     * you can use the timestamp to render the buffer at a specific time (at the
+     * VSYNC at or after the buffer timestamp).  For this to work, the timestamp
+     * needs to be <i>reasonably close</i> to the current {@link System#nanoTime}.
+     * Currently, this is set as within one (1) second. A few notes:
+     *
+     * <ul>
+     * <li>the buffer will not be returned to the codec until the timestamp
+     * has passed and the buffer is no longer used by the {@link android.view.Surface}.
+     * <li>buffers are processed sequentially, so you may block subsequent buffers to
+     * be displayed on the {@link android.view.Surface}.  This is important if you
+     * want to react to user action, e.g. stop the video or seek.
+     * <li>if multiple buffers are sent to the {@link android.view.Surface} to be
+     * rendered at the same VSYNC, the last one will be shown, and the other ones
+     * will be dropped.
+     * <li>if the timestamp is <em>not</em> "reasonably close" to the current system
+     * time, the {@link android.view.Surface} will ignore the timestamp, and
+     * display the buffer at the earliest feasible time.  In this mode it will not
+     * drop frames.
+     * <li>for best performance and quality, call this method when you are about
+     * two VSYNCs' time before the desired render time.  For 60Hz displays, this is
+     * about 33 msec.
+     * </ul>
+     * </td></tr>
+     * </table>
+     *
+     * @param index The index of a client-owned output buffer previously returned
+     *              from a call to {@link #dequeueOutputBuffer}.
+     * @param renderTimestampNs The timestamp to associate with this buffer when
+     *              it is sent to the Surface.
+     */
+    public final void releaseOutputBuffer(int index, long renderTimestampNs) {
+        releaseOutputBuffer(
+                index, true /* render */, true /* updatePTS */, renderTimestampNs);
+    }
+
+    private native final void releaseOutputBuffer(
+            int index, boolean render, boolean updatePTS, long timeNs);
 
     /**
      * Signals end-of-stream on input.  Equivalent to submitting an empty buffer with
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index ed98b96..90fe695 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -66,8 +66,6 @@
 
 LOCAL_CFLAGS +=
 
-LOCAL_LDLIBS := -lpthread
-
 LOCAL_MODULE:= libmedia_jni
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index a710c03..4a7c096 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -260,7 +260,11 @@
     return OK;
 }
 
-status_t JMediaCodec::releaseOutputBuffer(size_t index, bool render) {
+status_t JMediaCodec::releaseOutputBuffer(
+        size_t index, bool render, bool updatePTS, int64_t timestampNs) {
+    if (updatePTS) {
+        return mCodec->renderOutputBufferAndRelease(index, timestampNs);
+    }
     return render
         ? mCodec->renderOutputBufferAndRelease(index)
         : mCodec->releaseOutputBuffer(index);
@@ -873,7 +877,8 @@
 }
 
 static void android_media_MediaCodec_releaseOutputBuffer(
-        JNIEnv *env, jobject thiz, jint index, jboolean render) {
+        JNIEnv *env, jobject thiz,
+        jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
     ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
@@ -883,7 +888,7 @@
         return;
     }
 
-    status_t err = codec->releaseOutputBuffer(index, render);
+    status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
 
     throwExceptionAsNecessary(env, err);
 }
@@ -1138,7 +1143,7 @@
     { "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
       (void *)android_media_MediaCodec_dequeueOutputBuffer },
 
-    { "releaseOutputBuffer", "(IZ)V",
+    { "releaseOutputBuffer", "(IZZJ)V",
       (void *)android_media_MediaCodec_releaseOutputBuffer },
 
     { "signalEndOfInputStream", "()V",
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 2f2ea96..bf9f4ea 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -79,7 +79,8 @@
     status_t dequeueOutputBuffer(
             JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs);
 
-    status_t releaseOutputBuffer(size_t index, bool render);
+    status_t releaseOutputBuffer(
+            size_t index, bool render, bool updatePTS, int64_t timestampNs);
 
     status_t signalEndOfInputStream();
 
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index abebd48..6f42057 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -648,7 +648,7 @@
         return;
     }
 
-    clazz = env->FindClass("android/net/ProxyProperties");
+    clazz = env->FindClass("android/net/ProxyInfo");
     if (clazz == NULL) {
         return;
     }
@@ -660,7 +660,7 @@
         env->GetMethodID(clazz, "getPort", "()I");
 
     fields.proxyConfigGetExclusionList =
-        env->GetMethodID(clazz, "getExclusionList", "()Ljava/lang/String;");
+        env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;");
 }
 
 static void
diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml
index 546ddd4..0d943ed 100644
--- a/packages/Keyguard/res/layout/keyguard_status_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_status_view.xml
@@ -28,7 +28,7 @@
     androidprv:layout_maxWidth="@dimen/keyguard_security_width"
     androidprv:layout_maxHeight="@dimen/keyguard_security_height"
     android:gravity="center_horizontal|top"
-    android:layout_marginTop="32dp"
+    android:layout_marginTop="48dp"
     android:layout_marginBottom="32dp"
     android:contentDescription="@string/keyguard_accessibility_status">
     <LinearLayout
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..c779437
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
deleted file mode 100644
index 54dde82..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png
deleted file mode 100644
index 3c0dc4e..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png
deleted file mode 100644
index c526433..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png
deleted file mode 100644
index d13bc69..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png
deleted file mode 100644
index a137a80..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png
deleted file mode 100644
index 8da7945..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..98ba690
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
deleted file mode 100644
index 7cb52e3..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png
deleted file mode 100644
index 8010ce7..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..61947ea
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
deleted file mode 100644
index b9afa44..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png
deleted file mode 100644
index 6d46fdd..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..0b563b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png
deleted file mode 100644
index afdee8f..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png
deleted file mode 100644
index 7742207..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png
new file mode 100644
index 0000000..3600ee6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_lock_24dp.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_notifications.xml b/packages/SystemUI/res/drawable/ic_notifications.xml
deleted file mode 100644
index 97a7623..0000000
--- a/packages/SystemUI/res/drawable/ic_notifications.xml
+++ /dev/null
@@ -1,23 +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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"
-         android:drawable="@drawable/ic_notify_open_normal" />
-    <item
-         android:drawable="@drawable/ic_notify_open_normal" />
-</selector>
-
diff --git a/packages/SystemUI/res/drawable/ic_notify_clear.xml b/packages/SystemUI/res/drawable/ic_notify_clear.xml
deleted file mode 100644
index 2163198..0000000
--- a/packages/SystemUI/res/drawable/ic_notify_clear.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"
-        android:drawable="@drawable/ic_notify_clear_normal" />
-    <item android:drawable="@drawable/ic_notify_clear_normal" />
-</selector>
diff --git a/packages/SystemUI/res/drawable/notification_header_bg.xml b/packages/SystemUI/res/drawable/notification_header_bg.xml
new file mode 100644
index 0000000..b6b2e9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_header_bg.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
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <shape>
+            <solid android:color="#ff54656e" />
+            <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
+        </shape>
+    </item>
+    <item>
+        <shape>
+            <solid android:color="#ff384248" />
+            <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" />
+        </shape>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_dark.xml b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
new file mode 100644
index 0000000..c015cc8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_dismiss_dark.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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:versionCode="1" >
+
+    <size
+        android:height="16dp"
+        android:width="16dp" />
+
+    <viewport
+        android:viewportHeight="100"
+        android:viewportWidth="100" />
+
+    <group>
+        <path
+            android:name="x"
+            android:pathData="M0,0L100,100M0,100L100,0z"
+            android:stroke="@color/recents_task_bar_dark_dismiss_color"
+            android:strokeWidth="8.0"
+            android:strokeLineCap="square" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_light.xml b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
new file mode 100644
index 0000000..9c93db9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_dismiss_light.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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:versionCode="1" >
+
+    <size
+        android:height="16dp"
+        android:width="16dp" />
+
+    <viewport
+        android:viewportHeight="100"
+        android:viewportWidth="100" />
+
+    <group>
+        <path
+            android:name="x"
+            android:pathData="M0,0L100,100M0,100L100,0z"
+            android:stroke="@color/recents_task_bar_light_dismiss_color"
+            android:strokeWidth="8.0"
+            android:strokeLineCap="square" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-sw600dp/heads_up.xml b/packages/SystemUI/res/layout-sw600dp/heads_up.xml
index 71f7c21..f7035fe 100644
--- a/packages/SystemUI/res/layout-sw600dp/heads_up.xml
+++ b/packages/SystemUI/res/layout-sw600dp/heads_up.xml
@@ -25,7 +25,6 @@
         android:id="@+id/content_holder"
         android:layout_height="wrap_content"
         android:layout_width="@dimen/notification_panel_width"
-        android:layout_marginStart="@dimen/notification_panel_margin_left"
         android:background="@drawable/heads_up_window_bg"
         />
 </com.android.systemui.statusbar.policy.HeadsUpNotificationView>
diff --git a/packages/SystemUI/res/layout/flip_settings.xml b/packages/SystemUI/res/layout/flip_settings.xml
index f3c1b90..28d9625 100644
--- a/packages/SystemUI/res/layout/flip_settings.xml
+++ b/packages/SystemUI/res/layout/flip_settings.xml
@@ -22,5 +22,4 @@
     android:layout_height="wrap_content"
     android:background="#5f000000"
     android:animateLayoutChanges="true"
-    android:visibility="gone"
     android:columnCount="@integer/quick_settings_num_columns" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/heads_up.xml b/packages/SystemUI/res/layout/heads_up.xml
index 3a58b84..e4954e7 100644
--- a/packages/SystemUI/res/layout/heads_up.xml
+++ b/packages/SystemUI/res/layout/heads_up.xml
@@ -22,6 +22,5 @@
         android:layout_height="wrap_content"
         android:layout_width="@dimen/notification_panel_width"
         android:id="@+id/content_holder"
-        android:layout_marginStart="@dimen/notification_panel_margin_left"
         android:background="@drawable/notification_panel_bg"
         />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index ec5acba..194829d 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -55,4 +55,14 @@
         android:textStyle="italic"
         android:textAppearance="?android:attr/textAppearanceMedium"/>
 
+    <ImageView
+        android:layout_width="64dp"
+        android:layout_height="64dp"
+        android:layout_gravity="bottom|center_horizontal"
+        android:src="@drawable/ic_lock_24dp"
+        android:scaleType="center"
+        android:alpha="0.7"
+        android:layerType="hardware"
+        android:tint="#ffffffff"/>
+
 </com.android.systemui.statusbar.phone.KeyguardBottomAreaView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index f7df18eb..bda6431 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -63,6 +63,13 @@
             android:maxLines="2"
             android:ellipsize="marquee"
             android:fadingEdge="horizontal" />
+        <ImageView
+            android:id="@+id/dismiss_task"
+            android:layout_width="@dimen/recents_task_view_application_icon_size"
+            android:layout_height="@dimen/recents_task_view_application_icon_size"
+            android:layout_gravity="center_vertical|end"
+            android:padding="23dp"
+            android:src="@drawable/recents_dismiss_dark" />
     </com.android.systemui.recents.views.TaskBarView>
 </com.android.systemui.recents.views.TaskView>
 
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 1b35537..585658e 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -77,26 +77,24 @@
         <LinearLayout android:id="@+id/system_icon_area"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
-            android:orientation="horizontal">
-
-            <LinearLayout android:id="@+id/statusIcons"
+            android:orientation="horizontal"
+            >
+            <LinearLayout android:id="@+id/system_icons"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:gravity="center_vertical"
-                android:orientation="horizontal"/>    
-    
-            <LinearLayout
-                android:id="@+id/signal_battery_cluster"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:paddingStart="2dp"
-                android:orientation="horizontal"
-                android:gravity="center"
                 >
-                <include layout="@layout/signal_cluster_view" 
+                <LinearLayout android:id="@+id/statusIcons"
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    android:gravity="center_vertical"
+                    android:orientation="horizontal"/>
+
+                <include layout="@layout/signal_cluster_view"
                     android:id="@+id/signal_cluster"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
+                    android:layout_marginStart="2dp"
                     />
                 <!-- battery must be padded below to match assets -->
                 <com.android.systemui.BatteryMeterView
@@ -107,7 +105,6 @@
                     android:layout_marginStart="4dip"
                     />
             </LinearLayout>
-    
             <com.android.systemui.statusbar.policy.Clock
                 android:id="@+id/clock"
                 android:textAppearance="@style/TextAppearance.StatusBar.Clock"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 761ad42..d36f692 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -23,9 +23,7 @@
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/notification_panel"
     android:layout_width="0dp"
-    android:layout_height="wrap_content"
-    android:paddingTop="@dimen/notification_panel_padding_top"
-    android:layout_marginStart="@dimen/notification_panel_margin_left"
+    android:layout_height="match_parent"
     >
 
     <include
@@ -37,29 +35,6 @@
         />
 
     <include
-        layout="@layout/status_bar_flip_button"
-        android:id="@+id/keyguard_flipper"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_gravity="right|top"
-        android:layout_marginTop="@dimen/status_bar_height"
-        android:visibility="gone" />
-
-    <com.android.keyguard.CarrierText
-        android:id="@+id/keyguard_carrier_text"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="2dp"
-        android:layout_marginLeft="8dp"
-        android:ellipsize="marquee"
-        android:textAppearance="?android:attr/textAppearanceMedium" />
-
-    <include layout="@layout/status_bar_expanded_header"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/notification_panel_header_height"
-        />
-
-    <include
         layout="@layout/keyguard_status_view"
         android:layout_height="wrap_content"
         android:visibility="gone" />
@@ -74,27 +49,56 @@
         android:visibility="gone"
         />
 
-    <FrameLayout
+    <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
         android:id="@+id/notification_container_parent"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="@dimen/close_handle_underlap"
-        >
-        <include
-            layout="@layout/flip_settings"
-            android:layout_marginTop="@dimen/notification_panel_header_height"
+        android:clipToPadding="false"
+        android:clipChildren="false">
+
+        <com.android.systemui.statusbar.phone.ObservableScrollView
+            android:id="@+id/scroll_view"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            />
+            android:layout_height="match_parent"
+            android:visibility="invisible"
+            android:scrollbars="none"
+            android:fillViewport="true">
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+                <include
+                    layout="@layout/flip_settings"
+                    android:layout_marginTop="@dimen/status_bar_header_height_expanded"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"/>
+
+                <!-- A view to reserve space for the collapsed stack -->
+                <View
+                    android:layout_height="@dimen/collapsed_stack_height"
+                    android:layout_width="match_parent"/>
+            </LinearLayout>
+        </com.android.systemui.statusbar.phone.ObservableScrollView>
+
 
         <com.android.systemui.statusbar.stack.NotificationStackScrollLayout
             android:id="@+id/notification_stack_scroller"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            />
-    </FrameLayout>
+            android:layout_height="match_parent"
+            android:layout_marginBottom="@dimen/close_handle_underlap"/>
+
+    </com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>
+
+
+    <include layout="@layout/status_bar_expanded_header"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/status_bar_header_height"
+        android:layout_marginLeft="@dimen/notification_side_padding"
+        android:layout_marginRight="@dimen/notification_side_padding"
+        />
 
     <include
         layout="@layout/keyguard_bottom_area"
         android:visibility="gone" />
+
 </com.android.systemui.statusbar.phone.NotificationPanelView><!-- end of sliding panel -->
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 8975728..ac81e4e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -15,21 +15,31 @@
 ** limitations under the License.
 -->
 
-<LinearLayout
+<!-- Extends RelativeLayout -->
+<com.android.systemui.statusbar.phone.StatusBarHeaderView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/header"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/notification_panel_header_height"
-    android:background="@drawable/notification_header_bg"
+    android:layout_height="@dimen/status_bar_header_height"
     android:orientation="horizontal"
     android:gravity="center_vertical"
     android:baselineAligned="false"
+    android:elevation="14dp"
     >
+
+    <View
+        android:id="@+id/background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@drawable/notification_header_bg"
+        android:clickable="true"
+        />
     <RelativeLayout
         android:id="@+id/datetime"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
+        android:layout_gravity="start"
         android:paddingStart="8dp"
         android:paddingEnd="8dp"
         android:background="@drawable/ic_notify_button_bg"
@@ -55,12 +65,21 @@
             />
     </RelativeLayout>
 
-    <Space
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_weight="1"
-        />
+    <com.android.keyguard.CarrierText
+        android:id="@+id/keyguard_carrier_text"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/status_bar_header_height_keyguard"
+        android:layout_marginLeft="8dp"
+        android:gravity="center_vertical"
+        android:ellipsize="marquee"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
 
+    <FrameLayout android:id="@+id/system_icons_container"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/status_bar_header_height"
+        android:layout_alignParentEnd="true"
+        android:layout_marginEnd="16dp"
+        />
     <TextView
         android:id="@+id/header_debug_info"
         android:visibility="invisible"
@@ -74,18 +93,4 @@
         android:padding="2dp"
         />
 
-    <ImageView android:id="@+id/clear_all_button"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:scaleType="center"
-        android:src="@drawable/ic_notify_clear"
-        android:background="@drawable/ic_notify_button_bg"
-        android:contentDescription="@string/accessibility_clear_all"
-        />
-
-    <include layout="@layout/status_bar_flip_button"
-        android:id="@+id/header_flipper"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:layout_marginStart="12dp" />
-</LinearLayout>
+</com.android.systemui.statusbar.phone.StatusBarHeaderView>
diff --git a/packages/SystemUI/res/layout/status_bar_flip_button.xml b/packages/SystemUI/res/layout/status_bar_flip_button.xml
index b7dff8c..f4d7033 100644
--- a/packages/SystemUI/res/layout/status_bar_flip_button.xml
+++ b/packages/SystemUI/res/layout/status_bar_flip_button.xml
@@ -15,22 +15,11 @@
   ~ limitations under the License
   -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="50dp"
-        android:layout_height="50dp">
-    <ImageView android:id="@+id/settings_button"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:scaleType="center"
-        android:src="@drawable/ic_notify_settings"
-        android:background="@drawable/ic_notify_button_bg"
-        android:contentDescription="@string/accessibility_desc_quick_settings" />
-    <ImageView android:id="@+id/notification_button"
-        android:layout_width="50dp"
-        android:layout_height="50dp"
-        android:scaleType="center"
-        android:src="@drawable/ic_notifications"
-        android:background="@drawable/ic_notify_button_bg"
-        android:visibility="gone"
-        android:contentDescription="@string/accessibility_notifications_button" />
-</FrameLayout>
\ No newline at end of file
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/settings_button"
+    android:layout_width="50dp"
+    android:layout_height="50dp"
+    android:scaleType="center"
+    android:src="@drawable/ic_notify_quicksettings"
+    android:background="@drawable/ic_notify_button_bg"
+    android:contentDescription="@string/accessibility_desc_quick_settings"/>
\ No newline at end of file
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 2e08bff..30eedee 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="32dp"
+    android:layout_height="40dp"
     android:focusable="true"
     android:clickable="true"
     >
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 61d43d7..e95f3c3 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -33,12 +33,12 @@
     <com.android.systemui.statusbar.phone.PanelHolder
         android:id="@+id/panel_holder"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_marginTop="@dimen/panel_holder_padding_top">
+        android:layout_height="match_parent" >
         <include layout="@layout/status_bar_expanded"
             android:layout_width="@dimen/notification_panel_width"
-            android:layout_height="wrap_content"
-            android:layout_gravity="start|top" />
+            android:layout_height="match_parent"
+            android:layout_gravity="start|top"
+            android:visibility="gone" />
     </com.android.systemui.statusbar.phone.PanelHolder>
 
 </com.android.systemui.statusbar.phone.StatusBarWindowView>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index d8a3114..8ec48c8 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Onlangse programme"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Deursoek"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knoppie vir wissel van invoermetode."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Versoenbaarheid-zoem se knoppie."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoem kleiner na groter skerm."</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 9d1e036..7aaaaf3 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"የቅርብ ጊዜ  መተግበሪያዎች"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ፈልግ"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"ካሜራ"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"የግቤት ስልት አዝራር ቀይር"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"የተኳኋኝአጉላ አዝራር።"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"አነስተኛውን ማያ ወደ ትልቅ አጉላ።"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 22a032a..1c06615 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"التطبيقات الحديثة"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"بحث"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"الكاميرا"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"الهاتف"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"زر تبديل طريقة الإدخال."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"زر تكبير/تصغير للتوافق."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"استخدام التكبير/التصغير لتحويل شاشة صغيرة إلى شاشة أكبر"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 00ac707..febcab6 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Скорошни приложения"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Търсене"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Бутон за превключване на метода на въвеждане."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Бутон за промяна на мащаба с цел съвместимост."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Промяна на мащаба на екрана от по-малък до по-голям."</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index bfad5bc..658ece0 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Aplicacions recents"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Cerca"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Càmera"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botó de canvi del mètode d\'entrada."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botó de zoom de compatibilitat."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Amplia menys com més gran sigui la pantalla."</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 94ba5c7..c7d2703 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Nové aplikace"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Hledat"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparát"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačítko přepnutí metody zadávání"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačítko úpravy velikosti z důvodu kompatibility"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zvětšit menší obrázek na větší obrazovku."</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index df442ab..c740051 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Seneste apps"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Søg"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Skift indtastningsmetode-knappen."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knap for kompatibilitetszoom."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom mindre til større skærm."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 451476c..40ecc49 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Kürzlich geöffnete Apps"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Suchen"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefonnummer"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Schaltfläche zum Ändern der Eingabemethode"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Schaltfläche für Kompatibilitätszoom"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom auf einen größeren Bildschirm"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 6dcffcf..0e98ce0 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Πρόσφατες εφαρμογές"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Αναζήτηση"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Φωτογραφική μηχανή"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Τηλέφωνο"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Κουμπί εναλλαγής μεθόδου εισόδου"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Κουμπί εστίασης συμβατότητας."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Ζουμ από μικρότερη σε μεγαλύτερη οθόνη."</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 91a334a..f4098b7 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Recent apps"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Search"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Phone"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 91a334a..f4098b7 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Recent apps"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Search"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Phone"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 2150cbe..51198e6 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Aplicaciones recientes"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Buscar"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Cámara"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 3424166..1b73e18 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Aplicaciones recientes"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Buscar"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Cámara"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Teléfono"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 8dbf9af..0f95c60 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Hiljutised rakendused"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Otsing"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kaamera"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Sisestusmeetodi vahetamise nupp."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Sobivussuumi nupp."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Suumi suuremale ekraanile vähem."</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index b2ac990..f36d04b 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"برنامه‌های اخیر"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"جستجو"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"دوربین"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"کلید تغییر روش ورود متن."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"دکمه بزرگنمایی سازگار."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"بزرگنمایی از صفحه‌های کوچک تا بزرگ."</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index af0df4d..4ae3851 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Viimeaikaiset sovellukset"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Haku"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Syöttötavan vaihtopainike."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Yhteensopivuuszoomaus-painike."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoomaa pienemmältä suuremmalle ruudulle."</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index f01c99a..c55a5fc 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Applications récentes"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Rechercher"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Appareil photo"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 5efbd2f..1121918 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Applications récentes"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Rechercher"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Appareil photo"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index e6d38ef..f9e6aad 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"हाल ही के ऐप्स"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"खोजें"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"कैमरा"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"फ़ोन"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धति‍ बटन स्विच करें."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"संगतता ज़ूम बटन."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"छोटी से बड़ी स्‍क्रीन पर ज़ूम करें."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b777b8f..435f701 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Nedavne aplikacije"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Pretraži"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparat"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za promjenu načina unosa."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb za kompatibilnost zumiranja."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zumiranje manjeg zaslona na veći."</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 10732fe..7685477 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Legújabb alkalmazás"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Keresés"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Beviteli mód váltása gomb."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kompatibilitási zoom gomb."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kicsinyítsen a nagyobb képernyőhöz."</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index f1c4869..7a8ab10 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Վերջին ծրագրերը"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Որոնել"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Ֆոտոխցիկ"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Միացնել մուտքագրման եղանակի կոճակը:"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Համատեղելիության խոշորացման կոճակը:"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Դիտափոխել փոքրից ավելի մեծ էկրան:"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index f0b0713..cdb0816 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Apl terbaru"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Telusuri"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telepon"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tombol beralih metode masukan."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tombol perbesar/perkecil kompatibilitas."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Perbesar dari layar kecil ke besar."</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 6a57682..401dbce 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Applicazioni recenti"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Cerca"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Fotocamera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefono"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Pulsante per cambiare metodo di immissione."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Pulsante zoom compatibilità."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom inferiore per schermo più grande."</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 3e87b76..08ffc54 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"אפליקציות אחרונות"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"חפש"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"מצלמה"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"לחצן החלפת שיטת קלט."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"לחצן מרחק מתצוגה של תאימות."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"שנה מרחק מתצוגה של מסך קטן לגדול יותר."</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 1edb630..2caa069 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"最近使ったアプリ"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"検索"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"カメラ"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"入力方法の切り替えボタン。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"互換ズームボタン。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"小さい画面から大きい画面に拡大。"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 9d4344a..62e40d0 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"ბოლოს გამოყენებული აპები"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ძიება"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"კამერა"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"შეყვანის მეთოდის გადართვის ღილაკი."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"თავსებადი მასშტაბირების ღილაკი."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"შეცვალეთ პატარა ეკრანი უფრო დიდით."</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index bb2d3b9..35a6917 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"កម្មវិធី​ថ្មីៗ"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ស្វែងរក"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"ម៉ាស៊ីន​ថត"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ប្ដូរ​ប៊ូតុង​វិធីសាស្ត្រ​បញ្ចូល។"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ប៊ូតុង​ពង្រីក​ត្រូវ​គ្នា។"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ពង្រីក/បង្រួម​​អេក្រង់​ពី​​ទៅធំ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 83ffa9f..d7cd13b 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"최근에 사용한 앱"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"검색"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"카메라"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"입력 방법 버튼을 전환합니다."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"호환성 확대/축소 버튼입니다."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"작은 화면을 큰 화면으로 확대합니다."</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 9a3d483..991fb66 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"ແອັບຯຫຼ້າສຸດ"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ຊອກຫາ"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"ກ້ອງ"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"ໂທລະສັບ"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ປຸ່ມສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ປຸ່ມຊູມທີ່ໃຊ້ຮ່ວມກັນໄດ້."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ຊູມຈໍນ້ອຍໄປເປັນຈໍຂະຫນາດໃຫຍ່."</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 379cfce..87087b4 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Naujausios programos"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Ieškoti"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparatas"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefonas"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Perjungti įvesties metodo mygtuką."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Suderinamumo priartinimo mygtukas."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Padidinti ekraną."</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index ca07095..04571e7 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Nesen izmantotās lietotnes"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Meklēt"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Tālruņa numurs"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ievades metodes maiņas poga."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Saderības tālummaiņas poga."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Veikt tālummaiņu no mazāka ekrāna uz lielāku."</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 4545301..3e7b660 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Сүүлийн апп"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Хайх"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камер"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Оруулах аргыг сэлгэх товч."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Тохиромжтой өсгөх товч."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Жижгээс том дэлгэцрүү өсгөх."</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 587b84f..af50786 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Aplikasi terbaharu"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Cari"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Butang tukar kaedah input."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Butang zum keserasian."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Skrin zum lebih kecil kepada lebih besar."</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 001e733..9fa68b9 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Nylige apper"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Søk"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefonnummer"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bytt knapp for inndatametode."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoomknapp for kompatibilitet."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom fra mindre til større skjerm."</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 8a6e33b..8cf16bf 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Recente apps"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Zoeken"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefoon"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knop voor wijzigen invoermethode."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knop voor compatibiliteitszoom."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kleiner scherm uitzoomen naar groter scherm."</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 4862d1b..e51341d 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Ostatnie aplikacje"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Szukaj"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Aparat"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Przycisk przełączania metody wprowadzania."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Przycisk powiększenia na potrzeby zgodności."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Powiększa mniejszy ekran do większego."</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 012283a..11843b6 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Aplicações recentes"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Pesquisar"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Câmara"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telemóvel"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alternar botão de método de introdução."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão zoom de compatibilidade."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom menor para ecrã maior."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 0978d18..162d763 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Aplicativos recentes"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Pesquisar"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Câmera"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alterar botão do método de entrada."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão de zoom da compatibilidade."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aumentar a tela com zoom."</string>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 25f643f..9f82651 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -126,6 +126,8 @@
     <skip />
     <!-- no translation found for accessibility_camera_button (8064671582820358152) -->
     <skip />
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <!-- no translation found for accessibility_ime_switch_button (5032926134740456424) -->
     <skip />
     <!-- no translation found for accessibility_compatibility_zoom_button (8461115318742350699) -->
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 5c9764a..75ba35b 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Aplicaţii recente"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Căutați"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Cameră foto"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Buton pentru comutarea metodei de introducere."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Buton zoom pentru compatibilitate."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Faceţi zoom de la o imagine mai mică la una mai mare."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 976a793..6bdc6f4 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Недавние приложения"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Поиск"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка переключения способа ввода."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабирования (режим совместимости)"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Уменьшение изображения для увеличения свободного места на экране."</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 1224c3a..12c90ec 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Nové aplikácie"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Hľadať"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparát"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačidlo prepnutia metódy vstupu."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačidlo úpravy veľkosti z dôvodu kompatibility."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zväčšiť menší obrázok na väčšiu obrazovku."</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 10011bc..48d7727 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Nedavni programi"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Iskanje"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Fotoaparat"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za preklop načina vnosa."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb povečave za združljivost."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Povečava manjšega na večji zaslon."</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 0c6a939..dba27a1 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Недавне апликације"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Претражите"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Телефон"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Дугме Промени метод уноса."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Дугме Зум компатибилности."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Зумирање са мањег на већи екран."</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index d8bd1b1..0d58ed3 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Senaste apparna"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Sök"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Mobil"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knapp för byte av inmatningsmetod."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knapp för kompatibilitetszoom."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zooma mindre skärm till större."</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index d308b518..b626f78 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -76,6 +76,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Programu za hivi karibuni"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Tafuta"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Swichi kitufe cha mbinu ingizi."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kichupo cha kukuza kwa utangamanifu"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kuza kidogo kwa skrini kubwa."</string>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
deleted file mode 100644
index c6c0719..0000000
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ /dev/null
@@ -1,22 +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.
-*/
--->
-<resources>
-    <!-- Layout parameters for the notification panel -->
-	<dimen name="notification_panel_margin_bottom">0dp</dimen>
-    <dimen name="notification_panel_margin_left">32dp</dimen>
-</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 92e3885..7372181 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -19,10 +19,6 @@
     <!-- The width of the notification panel window: 446 + 16 + 16 (padding in the bg drawable) -->
     <dimen name="notification_panel_width">478dp</dimen>
 
-    <!-- Layout parameters for the notification panel -->
-    <dimen name="notification_panel_margin_bottom">192dp</dimen>
-    <dimen name="notification_panel_margin_left">16dp</dimen>
-
     <!-- Gravity for the notification panel -->
     <!-- 0x31 = top|center_horizontal -->
     <integer name="notification_panel_layout_gravity">0x31</integer>
@@ -43,9 +39,6 @@
     <dimen name="status_bar_recents_thumbnail_width">200dp</dimen>
     <dimen name="status_bar_recents_thumbnail_height">177dp</dimen>
 
-    <!-- On tablets, panels drop from the statusbar instead of overlapping it. -->
-    <dimen name="panel_holder_padding_top">@*android:dimen/status_bar_height</dimen>
-
     <!-- Minimum fraction of the screen that should be taken up by the notification panel. -->
     <item type="dimen" name="notification_panel_min_height_frac">40%</item>
 
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index b1fc00a..a1c5b66 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -24,8 +24,6 @@
 
     <!-- The width of the ticker, including the icon -->
     <dimen name="notification_ticker_width">360dp</dimen>
-    <!-- Status bar panel bottom offset (height of status bar - overlap) -->
-    <dimen name="status_bar_panel_bottom_offset">36dp</dimen>
     <!-- gap on either side of status bar notification icons -->
     <dimen name="status_bar_icon_padding">1dp</dimen>
     <!-- The width of the notification panel window -->
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 7929a30..6cb4a48 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"แอปพลิเคชันล่าสุด"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"ค้นหา"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"กล้องถ่ายรูป"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ปุ่มสลับวิธีการป้อนข้อมูล"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ปุ่มซูมที่ใช้งานร่วมกันได้"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ซูมหน้าจอให้มีขนาดใหญ่ขึ้น"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 92473a4..17e720e 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Kamakailang apps"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Hanapin"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Camera"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ilipat ang button na pamamaraan ng pag-input."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Button ng zoom ng pagiging tugma."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Mag-zoom nang mas maliit sa mas malaking screen."</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 9837ff8..1bf033f5 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Son uygulamalar"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Ara"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Giriş yöntemini değiştirme düğmesi."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Uyumluluk zum düğmesi."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Daha büyük ekrana daha küçük yakınlaştır."</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 534f520..a5284ae 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Останні програми"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Пошук"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Камера"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Номер телефону"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка перемикання методу введення."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабування сумісності."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Збільшення екрана."</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 56fc89c..8df2449 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Ứng dụng gần đây"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Tìm kiếm"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Máy ảnh"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Nút chuyển phương thức nhập."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Nút thu phóng khả năng tương thích."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Thu phóng màn hình lớn hơn hoặc nhỏ hơn."</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 442fdb7..8643ca8 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"最近运行的应用"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"搜索"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"相机"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"输入法切换按钮。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"兼容性缩放按钮。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"将小屏幕的图片放大在较大屏幕上显示。"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 54a3b1e..9d93094 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"最近使用的應用程式"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"搜尋"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"相機"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"電話"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index fc74f53..07b7841 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -78,6 +78,8 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"最近使用的應用程式"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"搜尋"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"相機"</string>
+    <!-- no translation found for accessibility_phone_button (6738112589538563574) -->
+    <skip />
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index dfe8838..48a1ace 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -78,6 +78,7 @@
     <string name="accessibility_recent" msgid="8571350598987952883">"Izinhlelo zokusebenza zakamuva"</string>
     <string name="accessibility_search_light" msgid="1103867596330271848">"Sesha"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Ikhamela"</string>
+    <string name="accessibility_phone_button" msgid="6738112589538563574">"Ifoni"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Vula indlela yokungena yenkinobho"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Inkinobho evumelekile yokusondeza"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Sondeza kancane esikrinini esikhudlwana"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 9281265..d23a3dc 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -30,7 +30,6 @@
     <drawable name="recents_callout_line">#99ffffff</drawable>
     <drawable name="notification_item_background_legacy_color">#ffaaaaaa</drawable>
     <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
-    <drawable name="notification_header_bg">#FF000000</drawable>
     <color name="notification_panel_scrim_color">#A0000000</color>
     <color name="notification_panel_scrim_color_keyguard">#80000000</color>
     <color name="batterymeter_frame_color">#66FFFFFF</color><!-- 40% white -->
@@ -53,10 +52,14 @@
     <!-- The default recents task bar background color. -->
     <color name="recents_task_bar_default_background_color">#e6444444</color>
     <!-- The default recents task bar text color. -->
-    <color name="recents_task_bar_default_text_color">#ffffffff</color>
+    <color name="recents_task_bar_default_text_color">#ffeeeeee</color>
     <!-- The recents task bar light text color to be drawn on top of dark backgrounds. -->
-    <color name="recents_task_bar_light_text_color">#ffffffff</color>
+    <color name="recents_task_bar_light_text_color">#ffeeeeee</color>
     <!-- The recents task bar dark text color to be drawn on top of light backgrounds. -->
     <color name="recents_task_bar_dark_text_color">#ff222222</color>
+    <!-- The recents task bar light dismiss icon color to be drawn on top of dark backgrounds. -->
+    <color name="recents_task_bar_light_dismiss_color">#ffeeeeee</color>
+    <!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. -->
+    <color name="recents_task_bar_dark_dismiss_color">#ff333333</color>
 
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c3ccb59..21eb41c 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -99,9 +99,6 @@
 
     <integer name="blinds_pop_duration_ms">10</integer>
 
-    <!-- The device supports quick settings. -->
-    <bool name="config_hasQuickSettings">true</bool>
-
     <!-- Should "4G" be shown instead of "LTE" when the network is NETWORK_TYPE_LTE? -->
     <bool name="config_show4GForLTE">true</bool>
 
@@ -121,6 +118,8 @@
     <integer name="recents_animate_task_bar_exit_duration">150</integer>
     <!-- The animation duration for animating in the info pane. -->
     <integer name="recents_animate_task_view_info_pane_duration">150</integer>
+    <!-- The animation duration for animating the removal of a task view. -->
+    <integer name="recents_animate_task_view_remove_duration">250</integer>
     <!-- The minimum alpha for the dim applied to cards that go deeper into the stack. -->
     <integer name="recents_max_task_stack_view_dim">96</integer>
     <!-- Transposes the search bar layout in landscape -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index d763bd6..f330b8e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -152,21 +152,14 @@
     <!-- Amount of close_handle that will NOT overlap the notification list -->
     <dimen name="close_handle_underlap">32dp</dimen>
 
-    <!-- Height of the notification panel header bar -->
-    <dimen name="notification_panel_header_height">48dp</dimen>
+    <!-- Height of the status bar header bar -->
+    <dimen name="status_bar_header_height">56dp</dimen>
 
-    <!-- Extra space above the panel -->
-    <dimen name="notification_panel_padding_top">0dp</dimen>
+    <!-- Height of the status bar header bar when expanded -->
+    <dimen name="status_bar_header_height_expanded">144dp</dimen>
 
-    <!-- Extra space above the clock in the panel -->
-    <dimen name="notification_panel_header_padding_top">0dp</dimen>
-
-    <!-- Extra space above the panel holder -->
-    <dimen name="panel_holder_padding_top">0dp</dimen>
-
-    <!-- Layout parameters for the notification panel -->
-    <dimen name="notification_panel_margin_bottom">0dp</dimen>
-    <dimen name="notification_panel_margin_left">0dp</dimen>
+    <!-- Height of the status bar header bar when on Keyguard -->
+    <dimen name="status_bar_header_height_keyguard">40dp</dimen>
 
     <!-- Gravity for the notification panel -->
     <!-- 0x37 = fill_horizontal|top -->
@@ -233,6 +226,9 @@
     <!-- The translation in the Z index for each task above the last task. -->
     <dimen name="recents_task_view_z_increment">5dp</dimen>
 
+    <!-- The amount to translate when animating the removal of a task. -->
+    <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
+
     <!-- The amount of space a user has to scroll to dismiss any info panes. -->
     <dimen name="recents_task_stack_scroll_dismiss_info_pane_distance">50dp</dimen>
 
@@ -261,6 +257,9 @@
     <!-- The padding between the individual notification cards. -->
     <dimen name="notification_padding">3dp</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>
+
     <!-- Width of the zen mode interstitial dialog. -->
     <dimen name="zen_mode_dialog_width">320dp</dimen>
 
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index e5168c4..6418930 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -18,13 +18,21 @@
 <resources>
     <item type="id" name="translation_y_animator_tag"/>
     <item type="id" name="translation_z_animator_tag"/>
+    <item type="id" name="scale_animator_tag"/>
     <item type="id" name="alpha_animator_tag"/>
     <item type="id" name="top_inset_animator_tag"/>
     <item type="id" name="height_animator_tag"/>
     <item type="id" name="translation_y_animator_end_value_tag"/>
     <item type="id" name="translation_z_animator_end_value_tag"/>
+    <item type="id" name="scale_animator_end_value_tag"/>
     <item type="id" name="alpha_animator_end_value_tag"/>
     <item type="id" name="top_inset_animator_end_value_tag"/>
     <item type="id" name="height_animator_end_value_tag"/>
+    <item type="id" name="translation_y_animator_start_value_tag"/>
+    <item type="id" name="translation_z_animator_start_value_tag"/>
+    <item type="id" name="scale_animator_start_value_tag"/>
+    <item type="id" name="alpha_animator_start_value_tag"/>
+    <item type="id" name="top_inset_animator_start_value_tag"/>
+    <item type="id" name="height_animator_start_value_tag"/>
 </resources>
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 396cb14..19a1b11 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -64,7 +64,7 @@
                 mSingleCountFirstTaskRect.offset(0, (int) statusBarHeight);
                 mMultipleCountFirstTaskRect = replyData.getParcelable(KEY_MULTIPLE_TASK_STACK_RECT);
                 mMultipleCountFirstTaskRect.offset(0, (int) statusBarHeight);
-                Console.log(Constants.DebugFlags.App.RecentsComponent,
+                Console.log(Constants.Log.App.RecentsComponent,
                         "[RecentsComponent|RecentsMessageHandler|handleMessage]",
                         "singleTaskRect: " + mSingleCountFirstTaskRect +
                         " multipleTaskRect: " + mMultipleCountFirstTaskRect);
@@ -83,7 +83,7 @@
     class RecentsServiceConnection implements ServiceConnection {
         @Override
         public void onServiceConnected(ComponentName className, IBinder service) {
-            Console.log(Constants.DebugFlags.App.RecentsComponent,
+            Console.log(Constants.Log.App.RecentsComponent,
                     "[RecentsComponent|ServiceConnection|onServiceConnected]",
                     "toggleRecents: " + mToggleRecentsUponServiceBound);
             mService = new Messenger(service);
@@ -103,7 +103,7 @@
 
         @Override
         public void onServiceDisconnected(ComponentName className) {
-            Console.log(Constants.DebugFlags.App.RecentsComponent,
+            Console.log(Constants.Log.App.RecentsComponent,
                     "[RecentsComponent|ServiceConnection|onServiceDisconnected]");
             mService = null;
             mServiceIsBound = false;
@@ -154,7 +154,7 @@
     }
 
     public void onStart() {
-        Console.log(Constants.DebugFlags.App.RecentsComponent, "[RecentsComponent|start]");
+        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|start]");
 
         // Try to create a long-running connection to the recents service
         bindToRecentsService(false);
@@ -162,11 +162,11 @@
 
     /** Toggles the alternate recents activity */
     public void onToggleRecents(Display display, int layoutDirection, View statusBarView) {
-        Console.logStartTracingTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                Constants.DebugFlags.App.TimeRecentsStartupKey);
-        Console.logStartTracingTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
-                Constants.DebugFlags.App.TimeRecentsLaunchKey);
-        Console.log(Constants.DebugFlags.App.RecentsComponent, "[RecentsComponent|toggleRecents]",
+        Console.logStartTracingTime(Constants.Log.App.TimeRecentsStartup,
+                Constants.Log.App.TimeRecentsStartupKey);
+        Console.logStartTracingTime(Constants.Log.App.TimeRecentsLaunchTask,
+                Constants.Log.App.TimeRecentsLaunchKey);
+        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|toggleRecents]",
                 "serviceIsBound: " + mServiceIsBound);
         mStatusBarView = statusBarView;
         if (!mServiceIsBound) {
@@ -192,7 +192,7 @@
     }
 
     public void onCloseRecents() {
-        Console.log(Constants.DebugFlags.App.RecentsComponent, "[RecentsComponent|closeRecents]");
+        Console.log(Constants.Log.App.RecentsComponent, "[RecentsComponent|closeRecents]");
         if (mServiceIsBound) {
             // Try and update the recents configuration
             try {
@@ -255,15 +255,10 @@
     /** Loads the first task thumbnail */
     Bitmap loadFirstTaskThumbnail() {
         SystemServicesProxy ssp = mSystemServicesProxy;
-        List<ActivityManager.RecentTaskInfo> tasks = ssp.getRecentTasks(1,
-                UserHandle.CURRENT.getIdentifier());
-        for (ActivityManager.RecentTaskInfo t : tasks) {
-            // Skip tasks in the home stack
-            if (ssp.isInHomeStack(t.persistentId)) {
-                return null;
-            }
+        List<ActivityManager.RunningTaskInfo> tasks = ssp.getRunningTasks(1);
 
-            return ssp.getTaskThumbnail(t.persistentId);
+        for (ActivityManager.RunningTaskInfo t : tasks) {
+            return ssp.getTaskThumbnail(t.id);
         }
         return null;
     }
@@ -286,17 +281,6 @@
         return (tasks.size() > 1);
     }
 
-    /** Returns whether the base intent of the top task stack was launched with the flag
-     * Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS. */
-    boolean isTopTaskExcludeFromRecents(List<ActivityManager.RecentTaskInfo> tasks) {
-        if (tasks.size() > 0) {
-            ActivityManager.RecentTaskInfo t = tasks.get(0);
-            Console.log(t.baseIntent.toString());
-            return (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
-        }
-        return false;
-    }
-
     /** Converts from the device rotation to the degree */
     float getDegreesForRotation(int value) {
         switch (value) {
@@ -400,10 +384,10 @@
                     mService.send(msg);
 
                     // Time this path
-                    Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                            Constants.DebugFlags.App.TimeRecentsStartupKey, "sendToggleRecents");
-                    Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
-                            Constants.DebugFlags.App.TimeRecentsLaunchKey, "sendToggleRecents");
+                    Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                            Constants.Log.App.TimeRecentsStartupKey, "sendToggleRecents");
+                    Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+                            Constants.Log.App.TimeRecentsLaunchKey, "sendToggleRecents");
                 } catch (RemoteException re) {
                     re.printStackTrace();
                 }
@@ -416,16 +400,14 @@
         }
 
         // Otherwise, Recents is not the front-most activity and we should animate into it.  If
-        // the activity at the root of the top task stack is excluded from recents, or if that
-        // task stack is in the home stack, then we just do a simple transition.  Otherwise, we
-        // animate to the rects defined by the Recents service, which can differ depending on the
-        // number of items in the list.
+        // the activity at the root of the top task stack in the home stack, then we just do a
+        // simple transition.  Otherwise, we animate to the rects defined by the Recents service,
+        // which can differ depending on the number of items in the list.
         List<ActivityManager.RecentTaskInfo> recentTasks =
-                ssp.getRecentTasks(4, UserHandle.CURRENT.getIdentifier());
+                ssp.getRecentTasks(2, UserHandle.CURRENT.getIdentifier());
         Rect taskRect = hasMultipleRecentsTask(recentTasks) ? mMultipleCountFirstTaskRect :
                 mSingleCountFirstTaskRect;
-        boolean isTaskExcludedFromRecents = isTopTaskExcludeFromRecents(recentTasks);
-        boolean useThumbnailTransition = !isTopTaskHome && !isTaskExcludedFromRecents &&
+        boolean useThumbnailTransition = !isTopTaskHome &&
                 hasValidTaskRects();
 
         if (useThumbnailTransition) {
@@ -450,8 +432,8 @@
             startAlternateRecentsActivity(opts, false);
         }
 
-        Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                Constants.DebugFlags.App.TimeRecentsStartupKey, "startRecentsActivity");
+        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                Constants.Log.App.TimeRecentsStartupKey, "startRecentsActivity");
         mLastToggleTime = System.currentTimeMillis();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java b/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
deleted file mode 100644
index 95ab8e8..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/BakedBezierInterpolator.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.android.systemui.recents;
-
-import android.animation.TimeInterpolator;
-
-/**
- * A pre-baked bezier-curved interpolator for quantum-paper transitions.
- */
-public class BakedBezierInterpolator implements TimeInterpolator {
-    public static final BakedBezierInterpolator INSTANCE = new BakedBezierInterpolator();
-
-    /**
-     * Use the INSTANCE variable instead of instantiating.
-     */
-    private BakedBezierInterpolator() {
-        super();
-    }
-
-    /**
-     * Lookup table values.
-     * Generated using a Bezier curve from (0,0) to (1,1) with control points:
-     * P0 (0,0)
-     * P1 (0.4, 0)
-     * P2 (0.2, 1.0)
-     * P3 (1.0, 1.0)
-     *
-     * Values sampled with x at regular intervals between 0 and 1.
-     */
-    private static final float[] VALUES = new float[] {
-        0.0f, 0.0002f, 0.0009f, 0.0019f, 0.0036f, 0.0059f, 0.0086f, 0.0119f, 0.0157f, 0.0209f,
-        0.0257f, 0.0321f, 0.0392f, 0.0469f, 0.0566f, 0.0656f, 0.0768f, 0.0887f, 0.1033f, 0.1186f,
-        0.1349f, 0.1519f, 0.1696f, 0.1928f, 0.2121f, 0.237f, 0.2627f, 0.2892f, 0.3109f, 0.3386f,
-        0.3667f, 0.3952f, 0.4241f, 0.4474f, 0.4766f, 0.5f, 0.5234f, 0.5468f, 0.5701f, 0.5933f,
-        0.6134f, 0.6333f, 0.6531f, 0.6698f, 0.6891f, 0.7054f, 0.7214f, 0.7346f, 0.7502f, 0.763f,
-        0.7756f, 0.7879f, 0.8f, 0.8107f, 0.8212f, 0.8326f, 0.8415f, 0.8503f, 0.8588f, 0.8672f,
-        0.8754f, 0.8833f, 0.8911f, 0.8977f, 0.9041f, 0.9113f, 0.9165f, 0.9232f, 0.9281f, 0.9328f,
-        0.9382f, 0.9434f, 0.9476f, 0.9518f, 0.9557f, 0.9596f, 0.9632f, 0.9662f, 0.9695f, 0.9722f,
-        0.9753f, 0.9777f, 0.9805f, 0.9826f, 0.9847f, 0.9866f, 0.9884f, 0.9901f, 0.9917f, 0.9931f,
-        0.9944f, 0.9955f, 0.9964f, 0.9973f, 0.9981f, 0.9986f, 0.9992f, 0.9995f, 0.9998f, 1.0f, 1.0f
-    };
-
-    private static final float STEP_SIZE = 1.0f / (VALUES.length - 1);
-
-    @Override
-    public float getInterpolation(float input) {
-        if (input >= 1.0f) {
-            return 1.0f;
-        }
-
-        if (input <= 0f) {
-            return 0f;
-        }
-
-        int position = Math.min(
-                (int)(input * (VALUES.length - 1)),
-                VALUES.length - 2);
-
-        float quantized = position * STEP_SIZE;
-        float difference = input - quantized;
-        float weight = difference / STEP_SIZE;
-
-        return VALUES[position] + weight * (VALUES[position + 1] - VALUES[position]);
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 90ea873..90998da 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -18,7 +18,6 @@
 
 /**
  * Constants
- * XXX: We are going to move almost all of these into a resource.
  */
 public class Constants {
     public static class DebugFlags {
@@ -26,12 +25,18 @@
         public static final boolean Verbose = false;
 
         public static class App {
+            // Enables the filtering of tasks according to their grouping
             public static final boolean EnableTaskFiltering = false;
+            // Enables clipping of tasks against each other
             public static final boolean EnableTaskStackClipping = false;
+            // Enables the use of theme colors as the task bar background
             public static final boolean EnableTaskBarThemeColors = true;
-            public static final boolean EnableInfoPane = true;
-            public static final boolean EnableSearchButton = true;
-
+            // Enables the info pane on long-press
+            public static final boolean EnableInfoPane = false;
+            // Enables the search bar layout
+            public static final boolean EnableSearchLayout = true;
+            // Enables the dynamic shadows behind each task
+            public static final boolean EnableShadows = false;
             // This disables the bitmap and icon caches
             public static final boolean DisableBackgroundCache = false;
             // For debugging, this enables us to create mock recents tasks
@@ -40,8 +45,11 @@
             public static final int SystemServicesProxyMockPackageCount = 3;
             // For debugging, this defines the number of mock recents tasks to create
             public static final int SystemServicesProxyMockTaskCount = 75;
+        }
+    }
 
-            // Timing certain paths
+    public static class Log {
+        public static class App {
             public static final String TimeRecentsStartupKey = "startup";
             public static final String TimeRecentsLaunchKey = "launchTask";
             public static final boolean TimeRecentsStartup = false;
@@ -72,6 +80,7 @@
         }
     }
 
+    /** XXX: We are going to move almost all of these into a resource once they are nailed down. */
     public static class Values {
         public static class App {
             public static int AppWidgetHostId = 1024;
@@ -102,10 +111,5 @@
             // The number of cards we see in the peek space
             public static final int StackPeekNumCards = 3;
         }
-
-        public static class TaskView {
-            public static final boolean AnimateFrontTaskBarOnEnterRecents = true;
-            public static final boolean AnimateFrontTaskBarOnLeavingRecents = true;
-        }
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 110130b..b74f6ac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -22,10 +22,10 @@
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.util.Pair;
 import android.view.LayoutInflater;
@@ -38,6 +38,7 @@
 import com.android.systemui.recents.views.RecentsView;
 
 import java.util.ArrayList;
+import java.util.Set;
 
 /** Our special app widget host */
 class RecentsAppWidgetHost extends AppWidgetHost {
@@ -61,7 +62,7 @@
 
 /* Activity */
 public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks,
-        RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks{
+        RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks {
     FrameLayout mContainerView;
     RecentsView mRecentsView;
     View mEmptyView;
@@ -78,7 +79,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-            Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+            Console.log(Constants.Log.App.SystemUIHandshake,
                     "[RecentsActivity|serviceBroadcast]", action, Console.AnsiRed);
             if (action.equals(RecentsService.ACTION_TOGGLE_RECENTS_ACTIVITY)) {
                 // Try and unfilter and filtered stacks
@@ -134,7 +135,7 @@
 
     /** Attempts to allocate and bind the search bar app widget */
     void bindSearchBarAppWidget() {
-        if (Constants.DebugFlags.App.EnableSearchButton) {
+        if (Constants.DebugFlags.App.EnableSearchLayout) {
             RecentsConfiguration config = RecentsConfiguration.getInstance();
             SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
 
@@ -152,7 +153,7 @@
                     ssp.unbindSearchAppWidget(mAppWidgetHost, appWidgetId);
                     appWidgetId = -1;
                 }
-                Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+                Console.log(Constants.Log.App.SystemUIHandshake,
                         "[RecentsActivity|onCreate|settings|appWidgetId]",
                         "Id: " + appWidgetId,
                         Console.AnsiBlue);
@@ -163,7 +164,7 @@
                 Pair<Integer, AppWidgetProviderInfo> widgetInfo =
                         ssp.bindSearchAppWidget(mAppWidgetHost);
                 if (widgetInfo != null) {
-                    Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+                    Console.log(Constants.Log.App.SystemUIHandshake,
                             "[RecentsActivity|onCreate|searchWidget]",
                             "Id: " + widgetInfo.first + " Info: " + widgetInfo.second,
                             Console.AnsiBlue);
@@ -178,11 +179,11 @@
 
     /** Creates the search bar app widget view */
     void addSearchBarAppWidgetView() {
-        if (Constants.DebugFlags.App.EnableSearchButton) {
+        if (Constants.DebugFlags.App.EnableSearchLayout) {
             RecentsConfiguration config = RecentsConfiguration.getInstance();
             int appWidgetId = config.searchBarAppWidgetId;
             if (appWidgetId >= 0) {
-                Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+                Console.log(Constants.Log.App.SystemUIHandshake,
                         "[RecentsActivity|onCreate|addSearchAppWidgetView]",
                         "Id: " + appWidgetId,
                         Console.AnsiBlue);
@@ -216,11 +217,11 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        Console.logDivider(Constants.DebugFlags.App.SystemUIHandshake);
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onCreate]",
+        Console.logDivider(Constants.Log.App.SystemUIHandshake);
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onCreate]",
                 getIntent().getAction() + " visible: " + mVisible, Console.AnsiRed);
-        Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                Constants.DebugFlags.App.TimeRecentsStartupKey, "onCreate");
+        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                Constants.Log.App.TimeRecentsStartupKey, "onCreate");
 
         // Initialize the loader and the configuration
         RecentsTaskLoader.initialize(this);
@@ -260,11 +261,11 @@
         // Reset the task launched flag if we encounter an onNewIntent() before onStop()
         mTaskLaunched = false;
 
-        Console.logDivider(Constants.DebugFlags.App.SystemUIHandshake);
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onNewIntent]",
+        Console.logDivider(Constants.Log.App.SystemUIHandshake);
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onNewIntent]",
                 intent.getAction() + " visible: " + mVisible, Console.AnsiRed);
-        Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                Constants.DebugFlags.App.TimeRecentsStartupKey, "onNewIntent");
+        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                Constants.Log.App.TimeRecentsStartupKey, "onNewIntent");
 
         // Initialize the loader and the configuration
         RecentsTaskLoader.initialize(this);
@@ -279,7 +280,7 @@
 
     @Override
     protected void onStart() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onStart]", "",
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStart]", "",
                 Console.AnsiRed);
         super.onStart();
         mAppWidgetHost.startListening();
@@ -288,14 +289,14 @@
 
     @Override
     protected void onResume() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onResume]", "",
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onResume]", "",
                 Console.AnsiRed);
         super.onResume();
     }
 
     @Override
     public void onAttachedToWindow() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+        Console.log(Constants.Log.App.SystemUIHandshake,
                 "[RecentsActivity|onAttachedToWindow]", "",
                 Console.AnsiRed);
         super.onAttachedToWindow();
@@ -309,11 +310,14 @@
         filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         registerReceiver(mScreenOffReceiver, filter);
+
+        // Register any broadcast receivers for the task loader
+        RecentsTaskLoader.getInstance().registerReceivers(this, mRecentsView);
     }
 
     @Override
     public void onDetachedFromWindow() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+        Console.log(Constants.Log.App.SystemUIHandshake,
                 "[RecentsActivity|onDetachedFromWindow]", "",
                 Console.AnsiRed);
         super.onDetachedFromWindow();
@@ -321,18 +325,19 @@
         // Unregister any broadcast receivers we have registered
         unregisterReceiver(mServiceBroadcastReceiver);
         unregisterReceiver(mScreenOffReceiver);
+        RecentsTaskLoader.getInstance().unregisterReceivers();
     }
 
     @Override
     protected void onPause() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onPause]", "",
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onPause]", "",
                 Console.AnsiRed);
         super.onPause();
     }
 
     @Override
     protected void onStop() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onStop]", "",
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onStop]", "",
                 Console.AnsiRed);
         super.onStop();
 
@@ -343,7 +348,7 @@
 
     @Override
     protected void onDestroy() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsActivity|onDestroy]", "",
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsActivity|onDestroy]", "",
                 Console.AnsiRed);
         super.onDestroy();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index d1a3954..9afc1cb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -23,6 +23,8 @@
 import android.graphics.Rect;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import com.android.systemui.R;
 
 
@@ -42,6 +44,8 @@
 
     public float animationPxMovementPerSecond;
 
+    public Interpolator defaultBezierInterpolator;
+
     public int filteringCurrentViewsMinAnimDuration;
     public int filteringNewViewsMinAnimDuration;
     public int taskBarEnterAnimDuration;
@@ -49,6 +53,8 @@
     public int taskStackScrollDismissInfoPaneDistance;
     public int taskStackMaxDim;
     public int taskViewInfoPaneAnimDuration;
+    public int taskViewRemoveAnimDuration;
+    public int taskViewRemoveAnimTranslationXPx;
     public int taskViewTranslationZMinPx;
     public int taskViewTranslationZIncrementPx;
     public int taskViewRoundedCornerRadiusPx;
@@ -88,7 +94,7 @@
                 Configuration.ORIENTATION_LANDSCAPE;
         transposeSearchLayoutWithOrientation =
                 res.getBoolean(R.bool.recents_transpose_search_layout_with_orientation);
-        Console.log(Constants.DebugFlags.UI.MeasureAndLayout,
+        Console.log(Constants.Log.UI.MeasureAndLayout,
                 "[RecentsConfiguration|orientation]", isLandscape ? "Landscape" : "Portrait",
                 Console.AnsiGreen);
 
@@ -108,6 +114,10 @@
         taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
         taskViewInfoPaneAnimDuration =
                 res.getInteger(R.integer.recents_animate_task_view_info_pane_duration);
+        taskViewRemoveAnimDuration =
+                res.getInteger(R.integer.recents_animate_task_view_remove_duration);
+        taskViewRemoveAnimTranslationXPx =
+                res.getDimensionPixelSize(R.dimen.recents_task_view_remove_anim_translation_x);
         taskViewRoundedCornerRadiusPx =
                 res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
         taskViewTranslationZMinPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
@@ -115,7 +125,6 @@
                 res.getDimensionPixelSize(R.dimen.recents_task_view_z_increment);
         searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
 
-
         taskBarViewDefaultBackgroundColor =
                 res.getColor(R.color.recents_task_bar_default_background_color);
         taskBarViewDefaultTextColor =
@@ -125,6 +134,9 @@
         taskBarViewDarkTextColor =
                 res.getColor(R.color.recents_task_bar_dark_text_color);
 
+        defaultBezierInterpolator = AnimationUtils.loadInterpolator(context,
+                        com.android.internal.R.interpolator.fast_out_slow_in);
+
         // Update the search widget id
         SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
         searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1);
@@ -174,7 +186,7 @@
      */
     public void getSearchBarBounds(int width, int height, Rect searchBarSpaceBounds) {
         // Return empty rects if search is not enabled
-        if (!Constants.DebugFlags.App.EnableSearchButton) {
+        if (!Constants.DebugFlags.App.EnableSearchLayout) {
             searchBarSpaceBounds.set(0, 0, 0, 0);
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java
new file mode 100644
index 0000000..4e620b6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsPackageMonitor.java
@@ -0,0 +1,112 @@
+/*
+ * 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.recents;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Looper;
+import com.android.internal.content.PackageMonitor;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * The package monitor listens for changes from PackageManager to update the contents of the Recents
+ * list.
+ */
+public class RecentsPackageMonitor extends PackageMonitor {
+    public interface PackageCallbacks {
+        public void onComponentRemoved(Set<ComponentName> cns);
+    }
+
+    PackageCallbacks mCb;
+    List<ActivityManager.RecentTaskInfo> mTasks;
+    SystemServicesProxy mSsp;
+
+    public RecentsPackageMonitor(Context context) {
+        mSsp = new SystemServicesProxy(context);
+    }
+
+    /** Registers the broadcast receivers with the specified callbacks. */
+    public void register(Context context, PackageCallbacks cb) {
+        mCb = cb;
+        register(context, Looper.getMainLooper(), false);
+    }
+
+    /** Unregisters the broadcast receivers. */
+    @Override
+    public void unregister() {
+        super.unregister();
+        mTasks.clear();
+    }
+
+    /** Sets the list of tasks to match against package broadcast changes. */
+    void setTasks(List<ActivityManager.RecentTaskInfo> tasks) {
+        mTasks = tasks;
+    }
+
+    @Override
+    public void onPackageRemoved(String packageName, int uid) {
+        if (mCb == null) return;
+
+        // Identify all the tasks that should be removed as a result of the package being removed.
+        // Using a set to ensure that we callback once per unique component.
+        HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>();
+        for (ActivityManager.RecentTaskInfo t : mTasks) {
+            ComponentName cn = t.baseIntent.getComponent();
+            if (cn.getPackageName().equals(packageName)) {
+                componentsToRemove.add(cn);
+            }
+        }
+        // Notify our callbacks that the components no longer exist
+        mCb.onComponentRemoved(componentsToRemove);
+    }
+
+    @Override
+    public boolean onPackageChanged(String packageName, int uid, String[] components) {
+        onPackageModified(packageName);
+        return true;
+    }
+
+    @Override
+    public void onPackageModified(String packageName) {
+        if (mCb == null) return;
+
+        // Identify all the tasks that should be removed as a result of the package being removed.
+        // Using a set to ensure that we callback once per unique component.
+        HashSet<ComponentName> componentsKnownToExist = new HashSet<ComponentName>();
+        HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>();
+        for (ActivityManager.RecentTaskInfo t : mTasks) {
+            ComponentName cn = t.baseIntent.getComponent();
+            if (cn.getPackageName().equals(packageName)) {
+                if (componentsKnownToExist.contains(cn)) {
+                    // If we know that the component still exists in the package, then skip
+                    continue;
+                }
+                if (mSsp.getActivityInfo(cn) != null) {
+                    componentsKnownToExist.add(cn);
+                } else {
+                    componentsToRemove.add(cn);
+                }
+            }
+        }
+        // Notify our callbacks that the components no longer exist
+        mCb.onComponentRemoved(componentsToRemove);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
index 0c6ed84..837cb34 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java
@@ -45,7 +45,7 @@
 
     @Override
     public void handleMessage(Message msg) {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake,
+        Console.log(Constants.Log.App.SystemUIHandshake,
                 "[RecentsService|handleMessage]", msg);
 
         Context context = mContext.get();
@@ -115,10 +115,10 @@
             context.sendBroadcast(intent);
 
             // Time this path
-            Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                    Constants.DebugFlags.App.TimeRecentsStartupKey, "receivedToggleRecents");
-            Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
-                    Constants.DebugFlags.App.TimeRecentsLaunchKey, "receivedToggleRecents");
+            Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                    Constants.Log.App.TimeRecentsStartupKey, "receivedToggleRecents");
+            Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+                    Constants.Log.App.TimeRecentsLaunchKey, "receivedToggleRecents");
         }
     }
 }
@@ -131,31 +131,31 @@
 
     @Override
     public void onCreate() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onCreate]");
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onCreate]");
         super.onCreate();
     }
 
     @Override
     public IBinder onBind(Intent intent) {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onBind]");
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onBind]");
         return mSystemUIMessenger.getBinder();
     }
 
     @Override
     public boolean onUnbind(Intent intent) {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onUnbind]");
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onUnbind]");
         return super.onUnbind(intent);
     }
 
     @Override
     public void onRebind(Intent intent) {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onRebind]");
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onRebind]");
         super.onRebind(intent);
     }
 
     @Override
     public void onDestroy() {
-        Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onDestroy]");
+        Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsService|onDestroy]");
         super.onDestroy();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
index 4a19027..1ca0476 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java
@@ -35,7 +35,6 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
@@ -51,7 +50,7 @@
 
     /** Adds a new task to the load queue */
     void addTask(Task t, boolean forceLoad) {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [TaskResourceLoadQueue|addTask]");
+        Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|addTask]");
         if (!mQueue.contains(t)) {
             mQueue.add(t);
         }
@@ -68,7 +67,7 @@
      * force reloaded.
      */
     Pair<Task, Boolean> nextTask() {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [TaskResourceLoadQueue|nextTask]");
+        Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|nextTask]");
         Task task = mQueue.poll();
         Boolean forceLoadTask = null;
         if (task != null) {
@@ -82,14 +81,14 @@
 
     /** Removes a task from the load queue */
     void removeTask(Task t) {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [TaskResourceLoadQueue|removeTask]");
+        Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|removeTask]");
         mQueue.remove(t);
         mForceLoadSet.remove(t.key);
     }
 
     /** Clears all the tasks from the load queue */
     void clearTasks() {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [TaskResourceLoadQueue|clearTasks]");
+        Console.log(Constants.Log.App.TaskDataLoader, "  [TaskResourceLoadQueue|clearTasks]");
         mQueue.clear();
         mForceLoadSet.clear();
     }
@@ -132,7 +131,7 @@
 
     /** Restarts the loader thread */
     void start(Context context) {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|start]");
+        Console.log(Constants.Log.App.TaskDataLoader, "[TaskResourceLoader|start]");
         mContext = context;
         mCancelled = false;
         mSystemServicesProxy = new SystemServicesProxy(context);
@@ -144,7 +143,7 @@
 
     /** Requests the loader thread to stop after the current iteration */
     void stop() {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|stop]");
+        Console.log(Constants.Log.App.TaskDataLoader, "[TaskResourceLoader|stop]");
         // Mark as cancelled for the thread to pick up
         mCancelled = true;
         mSystemServicesProxy = null;
@@ -158,10 +157,10 @@
     @Override
     public void run() {
         while (true) {
-            Console.log(Constants.DebugFlags.App.TaskDataLoader,
+            Console.log(Constants.Log.App.TaskDataLoader,
                     "[TaskResourceLoader|run|" + Thread.currentThread().getId() + "]");
             if (mCancelled) {
-                Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                Console.log(Constants.Log.App.TaskDataLoader,
                         "[TaskResourceLoader|cancel|" + Thread.currentThread().getId() + "]");
                 // We have to unset the context here, since the background thread may be using it
                 // when we call stop()
@@ -169,7 +168,7 @@
                 // If we are cancelled, then wait until we are started again
                 synchronized(mLoadThread) {
                     try {
-                        Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                        Console.log(Constants.Log.App.TaskDataLoader,
                                 "[TaskResourceLoader|waitOnLoadThreadCancelled]");
                         mLoadThread.wait();
                     } catch (InterruptedException ie) {
@@ -186,7 +185,7 @@
                 if (t != null) {
                     Drawable loadIcon = mApplicationIconCache.get(t.key);
                     Bitmap loadThumbnail = mThumbnailCache.get(t.key);
-                    Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                    Console.log(Constants.Log.App.TaskDataLoader,
                             "  [TaskResourceLoader|load]",
                             t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail +
                                     " forceLoad: " + forceLoadTask);
@@ -197,7 +196,7 @@
                         Drawable icon = ssp.getActivityIcon(info, t.userId);
                         if (!mCancelled) {
                             if (icon != null) {
-                                Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                                Console.log(Constants.Log.App.TaskDataLoader,
                                         "    [TaskResourceLoader|loadIcon]",
                                         icon);
                                 loadIcon = icon;
@@ -210,7 +209,7 @@
                         Bitmap thumbnail = ssp.getTaskThumbnail(t.key.id);
                         if (!mCancelled) {
                             if (thumbnail != null) {
-                                Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                                Console.log(Constants.Log.App.TaskDataLoader,
                                         "    [TaskResourceLoader|loadThumbnail]",
                                         thumbnail);
                                 thumbnail.setHasAlpha(false);
@@ -240,7 +239,7 @@
                 if (!mCancelled && mLoadQueue.isEmpty()) {
                     synchronized(mLoadQueue) {
                         try {
-                            Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                            Console.log(Constants.Log.App.TaskDataLoader,
                                     "[TaskResourceLoader|waitOnLoadQueue]");
                             mWaitingOnLoadQueue = true;
                             mLoadQueue.wait();
@@ -300,6 +299,8 @@
     TaskResourceLoadQueue mLoadQueue;
     TaskResourceLoader mLoader;
 
+    RecentsPackageMonitor mPackageMonitor;
+
     int mMaxThumbnailCacheSize;
     int mMaxIconCacheSize;
 
@@ -319,12 +320,13 @@
         int thumbnailCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :
                 mMaxThumbnailCacheSize;
 
-        Console.log(Constants.DebugFlags.App.TaskDataLoader,
+        Console.log(Constants.Log.App.TaskDataLoader,
                 "[RecentsTaskLoader|init]", "thumbnailCache: " + thumbnailCacheSize +
                 " iconCache: " + iconCacheSize);
 
         // Initialize the proxy, cache and loaders
         mSystemServicesProxy = new SystemServicesProxy(context);
+        mPackageMonitor = new RecentsPackageMonitor(context);
         mLoadQueue = new TaskResourceLoadQueue();
         mApplicationIconCache = new DrawableLruCache(iconCacheSize);
         mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
@@ -336,7 +338,7 @@
         mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
         mDefaultThumbnail.eraseColor(0x00000000);
         mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
-        Console.log(Constants.DebugFlags.App.TaskDataLoader,
+        Console.log(Constants.Log.App.TaskDataLoader,
                 "[RecentsTaskLoader|defaultBitmaps]",
                 "icon: " + mDefaultApplicationIcon + " thumbnail: " + mDefaultThumbnail, Console.AnsiRed);
     }
@@ -359,36 +361,19 @@
         return mSystemServicesProxy;
     }
 
-    private List<ActivityManager.RecentTaskInfo> getRecentTasks(Context context) {
+    private List<ActivityManager.RecentTaskInfo> getRecentTasks() {
         long t1 = System.currentTimeMillis();
 
         SystemServicesProxy ssp = mSystemServicesProxy;
         List<ActivityManager.RecentTaskInfo> tasks =
                 ssp.getRecentTasks(25, UserHandle.CURRENT.getIdentifier());
         Collections.reverse(tasks);
-        Console.log(Constants.DebugFlags.App.TimeSystemCalls,
+        Console.log(Constants.Log.App.TimeSystemCalls,
                 "[RecentsTaskLoader|getRecentTasks]",
                 "" + (System.currentTimeMillis() - t1) + "ms");
-        Console.log(Constants.DebugFlags.App.TaskDataLoader,
+        Console.log(Constants.Log.App.TaskDataLoader,
                 "[RecentsTaskLoader|tasks]", "" + tasks.size());
 
-        // Remove home/recents tasks
-        Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
-        while (iter.hasNext()) {
-            ActivityManager.RecentTaskInfo t = iter.next();
-
-            // Skip tasks in the home stack
-            if (ssp.isInHomeStack(t.persistentId)) {
-                iter.remove();
-                continue;
-            }
-            // Skip tasks from this Recents package
-            if (t.baseIntent.getComponent().getPackageName().equals(context.getPackageName())) {
-                iter.remove();
-                continue;
-            }
-        }
-
         return tasks;
     }
 
@@ -396,7 +381,7 @@
     SpaceNode reload(Context context, int preloadCount) {
         long t1 = System.currentTimeMillis();
 
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
+        Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|reload]");
         Resources res = context.getResources();
         ArrayList<Task> tasksToForceLoad = new ArrayList<Task>();
         TaskStack stack = new TaskStack(context);
@@ -405,7 +390,7 @@
 
         // Get the recent tasks
         SystemServicesProxy ssp = mSystemServicesProxy;
-        List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks(context);
+        List<ActivityManager.RecentTaskInfo> tasks = getRecentTasks();
 
         // Add each task to the task stack
         t1 = System.currentTimeMillis();
@@ -435,7 +420,7 @@
 
             // Preload the specified number of apps
             if (i >= (taskCount - preloadCount)) {
-                Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                Console.log(Constants.Log.App.TaskDataLoader,
                         "[RecentsTaskLoader|preloadTask]",
                         "i: " + i + " task: " + t.baseIntent.getComponent().getPackageName());
 
@@ -467,7 +452,7 @@
                     }
                 }
                 if (task.thumbnail == null) {
-                    Console.log(Constants.DebugFlags.App.TaskDataLoader,
+                    Console.log(Constants.Log.App.TaskDataLoader,
                             "[RecentsTaskLoader|loadingTaskThumbnail]");
                     task.thumbnail = ssp.getTaskThumbnail(task.key.id);
                     if (task.thumbnail != null) {
@@ -480,11 +465,11 @@
             }
 
             // Add the task to the stack
-            Console.log(Constants.DebugFlags.App.TaskDataLoader,
+            Console.log(Constants.Log.App.TaskDataLoader,
                 "  [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName());
             stack.addTask(task);
         }
-        Console.log(Constants.DebugFlags.App.TimeSystemCalls,
+        Console.log(Constants.Log.App.TimeSystemCalls,
                 "[RecentsTaskLoader|getAllTaskTopThumbnail]",
                 "" + (System.currentTimeMillis() - t1) + "ms");
 
@@ -492,10 +477,10 @@
         // Get all the stacks
         t1 = System.currentTimeMillis();
         List<ActivityManager.StackInfo> stackInfos = ams.getAllStackInfos();
-        Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms");
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size());
+        Console.log(Constants.Log.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms");
+        Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size());
         for (ActivityManager.StackInfo s : stackInfos) {
-            Console.log(Constants.DebugFlags.App.TaskDataLoader, "  [RecentsTaskLoader|stack]", s.toString());
+            Console.log(Constants.Log.App.TaskDataLoader, "  [RecentsTaskLoader|stack]", s.toString());
             if (stacks.containsKey(s.stackId)) {
                 stacks.get(s.stackId).setRect(s.bounds);
             }
@@ -510,6 +495,9 @@
             mLoadQueue.addTask(t, true);
         }
 
+        // Update the package monitor with the list of packages to listen for
+        mPackageMonitor.setTasks(tasks);
+
         return root;
     }
 
@@ -518,7 +506,7 @@
         Drawable applicationIcon = mApplicationIconCache.get(t.key);
         Bitmap thumbnail = mThumbnailCache.get(t.key);
 
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]",
+        Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]",
                 t + " applicationIcon: " + applicationIcon + " thumbnail: " + thumbnail +
                         " thumbnailCacheSize: " + mThumbnailCache.size());
 
@@ -539,7 +527,7 @@
 
     /** Releases the task resource data back into the pool. */
     public void unloadTaskData(Task t) {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader,
+        Console.log(Constants.Log.App.TaskDataLoader,
                 "[RecentsTaskLoader|unloadTask]", t +
                 " thumbnailCacheSize: " + mThumbnailCache.size());
 
@@ -548,25 +536,42 @@
     }
 
     /** Completely removes the resource data from the pool. */
-    public void deleteTaskData(Task t) {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader,
+    public void deleteTaskData(Task t, boolean notifyTaskDataUnloaded) {
+        Console.log(Constants.Log.App.TaskDataLoader,
                 "[RecentsTaskLoader|deleteTask]", t);
 
         mLoadQueue.removeTask(t);
         mThumbnailCache.remove(t.key);
         mApplicationIconCache.remove(t.key);
-        t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultApplicationIcon);
+        if (notifyTaskDataUnloaded) {
+            t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultApplicationIcon);
+        }
     }
 
     /** Stops the task loader and clears all pending tasks */
     void stopLoader() {
-        Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stopLoader]");
+        Console.log(Constants.Log.App.TaskDataLoader, "[RecentsTaskLoader|stopLoader]");
         mLoader.stop();
         mLoadQueue.clearTasks();
     }
 
+    /** Registers any broadcast receivers. */
+    public void registerReceivers(Context context, RecentsPackageMonitor.PackageCallbacks cb) {
+        // Register the broadcast receiver to handle messages related to packages being added/removed
+        mPackageMonitor.register(context, cb);
+    }
+
+    /** Unregisters any broadcast receivers. */
+    public void unregisterReceivers() {
+        mPackageMonitor.unregister();
+    }
+
+    /**
+     * Handles signals from the system, trimming memory when requested to prevent us from running
+     * out of memory.
+     */
     void onTrimMemory(int level) {
-        Console.log(Constants.DebugFlags.App.Memory, "[RecentsTaskLoader|onTrimMemory]",
+        Console.log(Constants.Log.App.Memory, "[RecentsTaskLoader|onTrimMemory]",
                 Console.trimMemoryLevelToString(level));
 
         switch (level) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
index c3b8a20..8d82883 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/SystemServicesProxy.java
@@ -30,7 +30,6 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
-import android.graphics.Rect;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
@@ -40,6 +39,7 @@
 import android.util.Pair;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Random;
 
@@ -54,7 +54,7 @@
     IPackageManager mIpm;
     UserManager mUm;
     SearchManager mSm;
-    String mPackage;
+    String mRecentsPackage;
     ComponentName mAssistComponent;
 
     Bitmap mDummyIcon;
@@ -67,7 +67,7 @@
         mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mIpm = AppGlobals.getPackageManager();
         mSm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
-        mPackage = context.getPackageName();
+        mRecentsPackage = context.getPackageName();
 
         // Resolve the assist intent
         Intent assist = mSm.getAssistIntent(context, false);
@@ -83,14 +83,14 @@
     }
 
     /** Returns a list of the recents tasks */
-    public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
+    public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId) {
         if (mAm == null) return null;
 
         // If we are mocking, then create some recent tasks
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
             ArrayList<ActivityManager.RecentTaskInfo> tasks =
                     new ArrayList<ActivityManager.RecentTaskInfo>();
-            int count = Math.min(numTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount);
+            int count = Math.min(numLatestTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount);
             for (int i = 0; i < count; i++) {
                 // Create a dummy component name
                 int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount;
@@ -114,9 +114,43 @@
             return tasks;
         }
 
-        return mAm.getRecentTasksForUser(numTasks,
+        // Remove home/recents/excluded tasks
+        int minNumTasksToQuery = 10;
+        int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks);
+        List<ActivityManager.RecentTaskInfo> tasks = mAm.getRecentTasksForUser(numTasksToQuery,
                 ActivityManager.RECENT_IGNORE_UNAVAILABLE |
-                        ActivityManager.RECENT_INCLUDE_PROFILES, userId);
+                ActivityManager.RECENT_INCLUDE_PROFILES |
+                ActivityManager.RECENT_WITH_EXCLUDED, userId);
+        boolean isFirstValidTask = true;
+        Iterator<ActivityManager.RecentTaskInfo> iter = tasks.iterator();
+        while (iter.hasNext()) {
+            ActivityManager.RecentTaskInfo t = iter.next();
+
+            // NOTE: The order of these checks happens in the expected order of the traversal of the
+            // tasks
+
+            // Skip tasks from this Recents package
+            if (t.baseIntent.getComponent().getPackageName().equals(mRecentsPackage)) {
+                iter.remove();
+                continue;
+            }
+            // Check the first non-recents task, include this task even if it is marked as excluded
+            // from recents.  In other words, only remove excluded tasks if it is not the first task
+            boolean isExcluded = (t.baseIntent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+                    == Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+            if (isExcluded && !isFirstValidTask) {
+                iter.remove();
+                continue;
+            }
+            isFirstValidTask = false;
+            // Skip tasks in the home stack
+            if (isInHomeStack(t.persistentId)) {
+                iter.remove();
+                continue;
+            }
+        }
+
+        return tasks.subList(0, Math.min(tasks.size(), numLatestTasks));
     }
 
     /** Returns a list of the running tasks */
@@ -165,11 +199,12 @@
     }
 
     /** Removes the task and kills the process */
-    public void removeTask(int taskId) {
+    public void removeTask(int taskId, boolean isDocument) {
         if (mAm == null) return;
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
 
-        mAm.removeTask(taskId, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+        // Remove the task, and only kill the process if it is not a document
+        mAm.removeTask(taskId, isDocument ? 0 : ActivityManager.REMOVE_TASK_KILL_PROCESS);
     }
 
     /**
@@ -180,7 +215,7 @@
      */
     public ActivityInfo getActivityInfo(ComponentName cn, int userId) {
         if (mIpm == null) return null;
-        if (Constants.DebugFlags.App.EnableSystemServicesProxy) return null;
+        if (Constants.DebugFlags.App.EnableSystemServicesProxy) return new ActivityInfo();
 
         try {
             return mIpm.getActivityInfo(cn, PackageManager.GET_META_DATA, userId);
@@ -197,7 +232,7 @@
      */
     public ActivityInfo getActivityInfo(ComponentName cn) {
         if (mPm == null) return null;
-        if (Constants.DebugFlags.App.EnableSystemServicesProxy) return null;
+        if (Constants.DebugFlags.App.EnableSystemServicesProxy) return new ActivityInfo();
 
         try {
             return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
index b602f84..46e6ee9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Utilities.java
@@ -18,6 +18,7 @@
 
 import android.graphics.Color;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 
 /* Common code */
 public class Utilities {
@@ -54,12 +55,15 @@
                 0.0722f * Color.blue(color));
     }
 
-    /** Returns the ideal text color to draw on top of a specified background color. */
-    public static int getIdealTextColorForBackgroundColor(int color) {
-        RecentsConfiguration configuration = RecentsConfiguration.getInstance();
+    /** Returns the ideal color to draw on top of a specified background color. */
+    public static int getIdealColorForBackgroundColor(int color, int lightRes, int darkRes) {
         int greyscale = colorToGreyscale(color);
-        return (greyscale < 128) ? configuration.taskBarViewLightTextColor :
-                configuration.taskBarViewDarkTextColor;
-
+        return (greyscale < 128) ? lightRes : darkRes;
+    }
+    /** Returns the ideal drawable to draw on top of a specified background color. */
+    public static Drawable getIdealResourceForBackgroundColor(int color, Drawable lightRes,
+                                                           Drawable darkRes) {
+        int greyscale = colorToGreyscale(color);
+        return (greyscale < 128) ? lightRes : darkRes;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index c2e8275..a6d7e67 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -19,6 +19,7 @@
 import android.app.ActivityOptions;
 import android.app.TaskStackBuilder;
 import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -33,19 +34,22 @@
 import com.android.systemui.recents.Console;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsPackageMonitor;
 import com.android.systemui.recents.RecentsTaskLoader;
 import com.android.systemui.recents.model.SpaceNode;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
 
 import java.util.ArrayList;
+import java.util.Set;
 
 
 /**
  * This view is the the top level layout that contains TaskStacks (which are laid out according
  * to their SpaceNode bounds.
  */
-public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks {
+public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks,
+        RecentsPackageMonitor.PackageCallbacks {
 
     /** The RecentsView callbacks */
     public interface RecentsViewCallbacks {
@@ -124,7 +128,7 @@
     /** Adds the search bar */
     public void setSearchBar(View searchBar) {
         // Create the search bar (and hide it if we have no recent tasks)
-        if (Constants.DebugFlags.App.EnableSearchButton) {
+        if (Constants.DebugFlags.App.EnableSearchLayout) {
             // Remove the previous search bar if one exists
             if (mSearchBar != null && indexOfChild(mSearchBar) > -1) {
                 removeView(mSearchBar);
@@ -135,7 +139,7 @@
                 mSearchBar.setVisibility(mHasTasks ? View.VISIBLE : View.GONE);
                 addView(mSearchBar);
 
-                Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsView|setSearchBar]",
+                Console.log(Constants.Log.App.SystemUIHandshake, "[RecentsView|setSearchBar]",
                         "" + (mSearchBar.getVisibility() == View.VISIBLE),
                         Console.AnsiBlue);
             }
@@ -152,10 +156,10 @@
         int height = MeasureSpec.getSize(heightMeasureSpec);
         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
 
-        Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|measure]",
+        Console.log(Constants.Log.UI.MeasureAndLayout, "[RecentsView|measure]",
                 "width: " + width + " height: " + height, Console.AnsiGreen);
-        Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onMeasure");
+        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                Constants.Log.App.TimeRecentsStartupKey, "RecentsView.onMeasure");
 
         // Get the search bar bounds and measure the search bar layout
         RecentsConfiguration config = RecentsConfiguration.getInstance();
@@ -194,10 +198,10 @@
      */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|layout]",
+        Console.log(Constants.Log.UI.MeasureAndLayout, "[RecentsView|layout]",
                 new Rect(left, top, right, bottom) + " changed: " + changed, Console.AnsiGreen);
-        Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsStartup,
-                Constants.DebugFlags.App.TimeRecentsStartupKey, "RecentsView.onLayout");
+        Console.logTraceTime(Constants.Log.App.TimeRecentsStartup,
+                Constants.Log.App.TimeRecentsStartupKey, "RecentsView.onLayout");
 
         // Get the search bar bounds so that we lay it out
         RecentsConfiguration config = RecentsConfiguration.getInstance();
@@ -232,14 +236,14 @@
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
-        Console.log(Constants.DebugFlags.UI.Draw, "[RecentsView|dispatchDraw]", "",
+        Console.log(Constants.Log.UI.Draw, "[RecentsView|dispatchDraw]", "",
                 Console.AnsiPurple);
         super.dispatchDraw(canvas);
     }
 
     @Override
     protected boolean fitSystemWindows(Rect insets) {
-        Console.log(Constants.DebugFlags.UI.MeasureAndLayout,
+        Console.log(Constants.Log.UI.MeasureAndLayout,
                 "[RecentsView|fitSystemWindows]", "insets: " + insets, Console.AnsiGreen);
 
         // Update the configuration with the latest system insets and trigger a relayout
@@ -342,7 +346,7 @@
                     RecentsTaskLoader.getInstance().getSystemServicesProxy()
                             .moveTaskToFront(task.key.id, opts);
                 } else {
-                    // Launch the activity with the desired animation
+                    // Launch the activity anew with the desired animation
                     Intent i = new Intent(task.key.baseIntent);
                     i.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
                             | Intent.FLAG_ACTIVITY_TASK_ON_HOME
@@ -357,18 +361,21 @@
                     } catch (ActivityNotFoundException anfe) {
                         Console.logError(getContext(), "Could not start Activity");
                     }
+
+                    // And clean up the old task
+                    onTaskRemoved(task);
                 }
 
-                Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
-                        Constants.DebugFlags.App.TimeRecentsLaunchKey, "startActivity");
+                Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+                        Constants.Log.App.TimeRecentsLaunchKey, "startActivity");
             }
         };
 
-        Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
-                Constants.DebugFlags.App.TimeRecentsLaunchKey, "onTaskLaunched");
+        Console.logTraceTime(Constants.Log.App.TimeRecentsLaunchTask,
+                Constants.Log.App.TimeRecentsLaunchKey, "onTaskLaunched");
 
         // Launch the app right away if there is no task view, otherwise, animate the icon out first
-        if (tv == null || !Constants.Values.TaskView.AnimateFrontTaskBarOnLeavingRecents) {
+        if (tv == null) {
             post(launchRunnable);
         } else {
             tv.animateOnLeavingRecents(launchRunnable);
@@ -385,4 +392,35 @@
         TaskStackBuilder.create(getContext())
                 .addNextIntentWithParentStack(intent).startActivities();
     }
+
+    @Override
+    public void onTaskRemoved(Task t) {
+        // Remove any stored data from the loader.  We currently don't bother notifying the views
+        // that the data has been unloaded because at the point we call onTaskRemoved(), the views
+        // either don't need to be updated, or have already been removed.
+        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        loader.deleteTaskData(t, false);
+
+        // Remove the old task from activity manager
+        int flags = t.key.baseIntent.getFlags();
+        boolean isDocument = (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) ==
+                Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+        RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(t.key.id,
+                isDocument);
+    }
+
+    /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
+
+    @Override
+    public void onComponentRemoved(Set<ComponentName> cns) {
+        // Propagate this event down to each task stack view
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = getChildAt(i);
+            if (child instanceof TaskStackView) {
+                TaskStackView stackView = (TaskStackView) child;
+                stackView.onComponentRemoved(cns);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
index 21ef9ff..c34300c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
@@ -178,7 +178,7 @@
     }
 
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        Console.log(Constants.DebugFlags.UI.TouchEvents,
+        Console.log(Constants.Log.UI.TouchEvents,
                 "[SwipeHelper|interceptTouchEvent]",
                 Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
         final int action = ev.getAction();
@@ -291,7 +291,7 @@
     }
 
     public boolean onTouchEvent(MotionEvent ev) {
-        Console.log(Constants.DebugFlags.UI.TouchEvents,
+        Console.log(Constants.Log.UI.TouchEvents,
                 "[SwipeHelper|touchEvent]",
                 Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
index c6cb812..07caa1b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskBarView.java
@@ -16,7 +16,10 @@
 
 package com.android.systemui.recents.views;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -32,9 +35,13 @@
 class TaskBarView extends FrameLayout {
     Task mTask;
 
+    ImageView mDismissButton;
     ImageView mApplicationIcon;
     TextView mActivityDescription;
 
+    Drawable mLightDismissDrawable;
+    Drawable mDarkDismissDrawable;
+
     public TaskBarView(Context context) {
         this(context, null);
     }
@@ -49,6 +56,9 @@
 
     public TaskBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        Resources res = context.getResources();
+        mLightDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_light);
+        mDarkDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_dark);
     }
 
     @Override
@@ -56,6 +66,28 @@
         // Initialize the icon and description views
         mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
         mActivityDescription = (TextView) findViewById(R.id.activity_description);
+        mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
+    }
+
+    /** Synchronizes this bar view's properties with the task's transform */
+    void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
+                                             TaskViewTransform toTransform, int duration) {
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        if (duration > 0) {
+            if (animateFromTransform != null) {
+                mDismissButton.setAlpha(animateFromTransform.dismissAlpha);
+            }
+            mDismissButton.animate()
+                    .alpha(toTransform.dismissAlpha)
+                    .setStartDelay(0)
+                    .setDuration(duration)
+                    .setInterpolator(config.defaultBezierInterpolator)
+                    .withLayer()
+                    .start();
+        } else {
+            mDismissButton.setAlpha(toTransform.dismissAlpha);
+        }
+        mDismissButton.invalidate();
     }
 
     /** Binds the bar view to the task */
@@ -74,7 +106,10 @@
         int tint = t.colorPrimary;
         if (Constants.DebugFlags.App.EnableTaskBarThemeColors && tint != 0) {
             setBackgroundColor(tint);
-            mActivityDescription.setTextColor(Utilities.getIdealTextColorForBackgroundColor(tint));
+            mActivityDescription.setTextColor(Utilities.getIdealColorForBackgroundColor(tint,
+                    configuration.taskBarViewLightTextColor, configuration.taskBarViewDarkTextColor));
+            mDismissButton.setImageDrawable(Utilities.getIdealResourceForBackgroundColor(tint,
+                    mLightDismissDrawable, mDarkDismissDrawable));
         } else {
             setBackgroundColor(configuration.taskBarViewDefaultBackgroundColor);
             mActivityDescription.setTextColor(configuration.taskBarViewDefaultTextColor);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
index c6c29a6..f1c362a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskInfoView.java
@@ -30,7 +30,6 @@
 import android.widget.Button;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
-import com.android.systemui.recents.BakedBezierInterpolator;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.Utilities;
@@ -111,7 +110,8 @@
         int duration = Utilities.calculateTranslationAnimationDuration((int) mMaxClipRadius);
         mCircularClipAnimator = ObjectAnimator.ofFloat(this, "circularClipRadius", toRadius);
         mCircularClipAnimator.setDuration(duration);
-        mCircularClipAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
+        mCircularClipAnimator.setInterpolator(
+                RecentsConfiguration.getInstance().defaultBezierInterpolator);
         mCircularClipAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
@@ -143,7 +143,7 @@
                 .scaleX(1f)
                 .scaleY(1f)
                 .setDuration(duration)
-                .setInterpolator(BakedBezierInterpolator.INSTANCE)
+                .setInterpolator(RecentsConfiguration.getInstance().defaultBezierInterpolator)
                 .withLayer()
                 .start();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index ce43b5a..b64225e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -18,11 +18,12 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.app.Activity;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -36,10 +37,10 @@
 import android.widget.FrameLayout;
 import android.widget.OverScroller;
 import com.android.systemui.R;
-import com.android.systemui.recents.BakedBezierInterpolator;
 import com.android.systemui.recents.Console;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsPackageMonitor;
 import com.android.systemui.recents.RecentsTaskLoader;
 import com.android.systemui.recents.Utilities;
 import com.android.systemui.recents.model.Task;
@@ -47,17 +48,19 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Set;
 
 
 /* The visual representation of a task stack view */
 public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCallbacks,
         TaskView.TaskViewCallbacks, ViewPool.ViewPoolConsumer<TaskView, Task>,
-        View.OnClickListener, View.OnLongClickListener {
+        View.OnClickListener, View.OnLongClickListener, RecentsPackageMonitor.PackageCallbacks {
 
     /** The TaskView callbacks */
     interface TaskStackViewCallbacks {
         public void onTaskLaunched(TaskStackView stackView, TaskView tv, TaskStack stack, Task t);
         public void onTaskAppInfoLaunched(Task t);
+        public void onTaskRemoved(Task t);
     }
 
     TaskStack mStack;
@@ -110,7 +113,7 @@
         requestSynchronizeStackViewsWithModel(0);
     }
     void requestSynchronizeStackViewsWithModel(int duration) {
-        Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+        Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
                 "[TaskStackView|requestSynchronize]", "" + duration + "ms", Console.AnsiYellow);
         if (!mStackViewsDirty) {
             invalidate();
@@ -166,6 +169,9 @@
             transform.translationY = (int) (boundedT * overlapHeight - scaleYOffset);
         }
 
+        // Set the alphas
+        transform.dismissAlpha = Math.max(-1f, Math.min(0f, t)) + 1f;
+
         // Update the rect and visibility
         transform.rect.set(mTaskRect);
         if (t < -(numPeekCards + 1)) {
@@ -215,7 +221,7 @@
 
     /** Synchronizes the views with the model */
     void synchronizeStackViewsWithModel() {
-        Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+        Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
                 "[TaskStackView|synchronizeViewsWithModel]",
                 "mStackViewsDirty: " + mStackViewsDirty, Console.AnsiYellow);
         if (mStackViewsDirty) {
@@ -271,7 +277,7 @@
                 }
             }
 
-            Console.log(Constants.DebugFlags.TaskStack.SynchronizeViewsWithModel,
+            Console.log(Constants.Log.TaskStack.SynchronizeViewsWithModel,
                     "  [TaskStackView|viewChildren]", "" + getChildCount());
 
             mStackViewsAnimationDuration = 0;
@@ -334,7 +340,7 @@
         mScrollAnimator = ObjectAnimator.ofInt(this, "stackScroll", curScroll, newScroll);
         mScrollAnimator.setDuration(Utilities.calculateTranslationAnimationDuration(newScroll -
                 curScroll, 250));
-        mScrollAnimator.setInterpolator(BakedBezierInterpolator.INSTANCE);
+        mScrollAnimator.setInterpolator(RecentsConfiguration.getInstance().defaultBezierInterpolator);
         mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
@@ -429,7 +435,7 @@
         }
 
         // Debug logging
-        if (Constants.DebugFlags.UI.MeasureAndLayout) {
+        if (Constants.Log.UI.MeasureAndLayout) {
             Console.log("  [TaskStack|minScroll] " + mMinScroll);
             Console.log("  [TaskStack|maxScroll] " + mMaxScroll);
         }
@@ -456,7 +462,7 @@
 
     /** Enables the hw layers and increments the hw layer requirement ref count */
     void addHwLayersRefCount(String reason) {
-        Console.log(Constants.DebugFlags.UI.HwLayers,
+        Console.log(Constants.Log.UI.HwLayers,
                 "[TaskStackView|addHwLayersRefCount] refCount: " +
                         mHwLayersRefCount + "->" + (mHwLayersRefCount + 1) + " " + reason);
         if (mHwLayersRefCount == 0) {
@@ -473,7 +479,7 @@
     /** Decrements the hw layer requirement ref count and disables the hw layers when we don't
         need them anymore. */
     void decHwLayersRefCount(String reason) {
-        Console.log(Constants.DebugFlags.UI.HwLayers,
+        Console.log(Constants.Log.UI.HwLayers,
                 "[TaskStackView|decHwLayersRefCount] refCount: " +
                         mHwLayersRefCount + "->" + (mHwLayersRefCount - 1) + " " + reason);
         mHwLayersRefCount--;
@@ -515,7 +521,7 @@
 
     @Override
     public void dispatchDraw(Canvas canvas) {
-        Console.log(Constants.DebugFlags.UI.Draw, "[TaskStackView|dispatchDraw]", "",
+        Console.log(Constants.Log.UI.Draw, "[TaskStackView|dispatchDraw]", "",
                 Console.AnsiPurple);
         synchronizeStackViewsWithModel();
         super.dispatchDraw(canvas);
@@ -568,7 +574,7 @@
 
         int smallestDimension = Math.min(width, height);
         int padding = (int) (Constants.Values.TaskStackView.StackPaddingPct * smallestDimension / 2f);
-        if (Constants.DebugFlags.App.EnableSearchButton) {
+        if (Constants.DebugFlags.App.EnableSearchLayout) {
             mStackRect.top += padding;
             mStackRect.left += padding;
             mStackRect.right -= padding;
@@ -600,7 +606,7 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int width = MeasureSpec.getSize(widthMeasureSpec);
         int height = MeasureSpec.getSize(heightMeasureSpec);
-        Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[TaskStackView|measure]",
+        Console.log(Constants.Log.UI.MeasureAndLayout, "[TaskStackView|measure]",
                 "width: " + width + " height: " + height +
                 " awaitingFirstLayout: " + mAwaitingFirstLayout, Console.AnsiGreen);
 
@@ -611,7 +617,7 @@
         computeRects(width, height, taskStackBounds.left, config.systemInsets.bottom);
 
         // Debug logging
-        if (Constants.DebugFlags.UI.MeasureAndLayout) {
+        if (Constants.Log.UI.MeasureAndLayout) {
             Console.log("  [TaskStack|fullRect] " + mRect);
             Console.log("  [TaskStack|stackRect] " + mStackRect);
             Console.log("  [TaskStack|stackRectSansPeek] " + mStackRectSansPeek);
@@ -626,8 +632,7 @@
             synchronizeStackViewsWithModel();
 
             // Animate the task bar of the first task view
-            if (config.launchedWithThumbnailAnimation &&
-                    Constants.Values.TaskView.AnimateFrontTaskBarOnEnterRecents) {
+            if (config.launchedWithThumbnailAnimation) {
                 TaskView tv = (TaskView) getChildAt(getChildCount() - 1);
                 if (tv != null) {
                     tv.animateOnEnterRecents();
@@ -653,11 +658,11 @@
      */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[TaskStackView|layout]",
+        Console.log(Constants.Log.UI.MeasureAndLayout, "[TaskStackView|layout]",
                 "" + new Rect(left, top, right, bottom), Console.AnsiGreen);
 
         // Debug logging
-        if (Constants.DebugFlags.UI.MeasureAndLayout) {
+        if (Constants.Log.UI.MeasureAndLayout) {
             Console.log("  [TaskStack|fullRect] " + mRect);
             Console.log("  [TaskStack|stackRect] " + mStackRect);
             Console.log("  [TaskStack|stackRectSansPeek] " + mStackRectSansPeek);
@@ -707,9 +712,24 @@
             }
         }
 
+        // Update the min/max scroll and animate other task views into their new positions
         updateMinMaxScroll(true);
         int movement = (int) (Constants.Values.TaskStackView.StackOverlapPct * mTaskRect.height());
         requestSynchronizeStackViewsWithModel(Utilities.calculateTranslationAnimationDuration(movement));
+
+        // If there are no remaining tasks, then either unfilter the current stack, or just close
+        // the activity if there are no filtered stacks
+        if (mStack.getTaskCount() == 0) {
+            boolean shouldFinishActivity = true;
+            if (mStack.hasFilteredTasks()) {
+                mStack.unfilterTasks();
+                shouldFinishActivity = (mStack.getTaskCount() == 0);
+            }
+            if (shouldFinishActivity) {
+                Activity activity = (Activity) getContext();
+                activity.finish();
+            }
+        }
     }
 
     /**
@@ -911,7 +931,7 @@
 
     @Override
     public TaskView createView(Context context) {
-        Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, "[TaskStackView|createPoolView]");
+        Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|createPoolView]");
         return (TaskView) mInflater.inflate(R.layout.recents_task_view, this, false);
     }
 
@@ -919,7 +939,7 @@
     public void prepareViewToEnterPool(TaskView tv) {
         Task task = tv.getTask();
         tv.resetViewProperties();
-        Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, "[TaskStackView|returnToPool]",
+        Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|returnToPool]",
                 tv.getTask() + " tv: " + tv);
 
         // Report that this tasks's data is no longer being used
@@ -935,7 +955,7 @@
 
     @Override
     public void prepareViewToLeavePool(TaskView tv, Task prepareData, boolean isNewView) {
-        Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, "[TaskStackView|leavePool]",
+        Console.log(Constants.Log.ViewPool.PoolCallbacks, "[TaskStackView|leavePool]",
                 "isNewView: " + isNewView);
 
         // Setup and attach the view to the window
@@ -958,7 +978,7 @@
         }
 
         // Add/attach the view to the hierarchy
-        Console.log(Constants.DebugFlags.ViewPool.PoolCallbacks, "  [TaskStackView|insertIndex]",
+        Console.log(Constants.Log.ViewPool.PoolCallbacks, "  [TaskStackView|insertIndex]",
                 "" + insertIndex);
         if (isNewView) {
             addView(tv, insertIndex);
@@ -988,7 +1008,7 @@
 
     @Override
     public void onTaskIconClicked(TaskView tv) {
-        Console.log(Constants.DebugFlags.UI.ClickEvents, "[TaskStack|Clicked|Icon]",
+        Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Icon]",
                 tv.getTask() + " is currently filtered: " + mStack.hasFilteredTasks(),
                 Console.AnsiCyan);
         if (Constants.DebugFlags.App.EnableTaskFiltering) {
@@ -1018,13 +1038,22 @@
         }
     }
 
+    @Override
+    public void onTaskDismissed(TaskView tv) {
+        Task task = tv.getTask();
+        // Remove the task from the view
+        mStack.removeTask(task);
+        // Notify the callback that we've removed the task and it can clean up after it
+        mCb.onTaskRemoved(task);
+    }
+
     /**** View.OnClickListener Implementation ****/
 
     @Override
     public void onClick(View v) {
         TaskView tv = (TaskView) v;
         Task task = tv.getTask();
-        Console.log(Constants.DebugFlags.UI.ClickEvents, "[TaskStack|Clicked|Thumbnail]",
+        Console.log(Constants.Log.UI.ClickEvents, "[TaskStack|Clicked|Thumbnail]",
                 task + " cb: " + mCb);
 
         // Close any open info panes if the user taps on another task
@@ -1072,6 +1101,33 @@
         tv.showInfoPane(new Rect(0, 0, 0, (int) overlapHeight));
         return true;
     }
+
+    /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
+
+    @Override
+    public void onComponentRemoved(Set<ComponentName> cns) {
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        // For other tasks, just remove them directly if they no longer exist
+        ArrayList<Task> tasks = mStack.getTasks();
+        for (int i = tasks.size() - 1; i >= 0; i--) {
+            final Task t = tasks.get(i);
+            if (cns.contains(t.key.baseIntent.getComponent())) {
+                TaskView tv = getChildViewForTask(t);
+                if (tv != null) {
+                    // For visible children, defer removing the task until after the animation
+                    tv.animateRemoval(new Runnable() {
+                        @Override
+                        public void run() {
+                            mStack.removeTask(t);
+                        }
+                    });
+                } else {
+                    // Otherwise, remove the task from the stack immediately
+                    mStack.removeTask(t);
+                }
+            }
+        }
+    }
 }
 
 /* Handles touch events */
@@ -1149,7 +1205,7 @@
 
     /** Touch preprocessing for handling below */
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        Console.log(Constants.DebugFlags.UI.TouchEvents,
+        Console.log(Constants.Log.UI.TouchEvents,
                 "[TaskStackViewTouchHandler|interceptTouchEvent]",
                 Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
 
@@ -1233,7 +1289,7 @@
 
     /** Handles touch events once we have intercepted them */
     public boolean onTouchEvent(MotionEvent ev) {
-        Console.log(Constants.DebugFlags.UI.TouchEvents,
+        Console.log(Constants.Log.UI.TouchEvents,
                 "[TaskStackViewTouchHandler|touchEvent]",
                 Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue);
 
@@ -1336,7 +1392,7 @@
                             Math.abs((float) velocity / mMaximumVelocity)) *
                             Constants.Values.TaskStackView.TaskStackOverscrollRange);
 
-                    Console.log(Constants.DebugFlags.UI.TouchEvents,
+                    Console.log(Constants.Log.UI.TouchEvents,
                             "[TaskStackViewTouchHandler|fling]",
                             "scroll: " + mSv.getStackScroll() + " velocity: " + velocity +
                                     " maxVelocity: " + mMaximumVelocity +
@@ -1433,31 +1489,7 @@
     @Override
     public void onChildDismissed(View v) {
         TaskView tv = (TaskView) v;
-        Task task = tv.getTask();
-        Activity activity = (Activity) mSv.getContext();
-
-        // Remove the task from the view
-        mSv.mStack.removeTask(task);
-
-        // Remove any stored data from the loader
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-        loader.deleteTaskData(task);
-
-        // Remove the task from activity manager
-        RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(tv.getTask().key.id);
-
-        // If there are no remaining tasks, then either unfilter the current stack, or just close
-        // the activity if there are no filtered stacks
-        if (mSv.mStack.getTaskCount() == 0) {
-            boolean shouldFinishActivity = true;
-            if (mSv.mStack.hasFilteredTasks()) {
-                mSv.mStack.unfilterTasks();
-                shouldFinishActivity = (mSv.mStack.getTaskCount() == 0);
-            }
-            if (shouldFinishActivity) {
-                activity.finish();
-            }
-        }
+        mSv.onTaskDismissed(tv);
 
         // Disable HW layers
         mSv.decHwLayersRefCount("swipeComplete");
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 801de24..5fad629 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -31,7 +31,6 @@
 import android.view.animation.AccelerateInterpolator;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
-import com.android.systemui.recents.BakedBezierInterpolator;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.model.Task;
@@ -46,6 +45,7 @@
         public void onTaskInfoPanelShown(TaskView tv);
         public void onTaskInfoPanelHidden(TaskView tv);
         public void onTaskAppInfoClicked(TaskView tv);
+        public void onTaskDismissed(TaskView tv);
 
         // public void onTaskViewReboundToTask(TaskView tv, Task t);
     }
@@ -143,21 +143,29 @@
         int minZ = config.taskViewTranslationZMinPx;
         int incZ = config.taskViewTranslationZIncrementPx;
 
+        // Update the bar view
+        mBarView.updateViewPropertiesToTaskTransform(animateFromTransform, toTransform, duration);
+
+        // Update this task view
         if (duration > 0) {
             if (animateFromTransform != null) {
                 setTranslationY(animateFromTransform.translationY);
-                setTranslationZ(Math.max(minZ, minZ + (animateFromTransform.t * incZ)));
+                if (Constants.DebugFlags.App.EnableShadows) {
+                    setTranslationZ(Math.max(minZ, minZ + (animateFromTransform.t * incZ)));
+                }
                 setScaleX(animateFromTransform.scale);
                 setScaleY(animateFromTransform.scale);
                 setAlpha(animateFromTransform.alpha);
             }
+            if (Constants.DebugFlags.App.EnableShadows) {
+                animate().translationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
+            }
             animate().translationY(toTransform.translationY)
-                    .translationZ(Math.max(minZ, minZ + (toTransform.t * incZ)))
                     .scaleX(toTransform.scale)
                     .scaleY(toTransform.scale)
                     .alpha(toTransform.alpha)
                     .setDuration(duration)
-                    .setInterpolator(BakedBezierInterpolator.INSTANCE)
+                    .setInterpolator(config.defaultBezierInterpolator)
                     .withLayer()
                     .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                         @Override
@@ -168,7 +176,9 @@
                     .start();
         } else {
             setTranslationY(toTransform.translationY);
-            setTranslationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
+            if (Constants.DebugFlags.App.EnableShadows) {
+                setTranslationZ(Math.max(minZ, minZ + (toTransform.t * incZ)));
+            }
             setScaleX(toTransform.scale);
             setScaleY(toTransform.scale);
             setAlpha(toTransform.alpha);
@@ -181,7 +191,9 @@
     void resetViewProperties() {
         setTranslationX(0f);
         setTranslationY(0f);
-        setTranslationZ(0f);
+        if (Constants.DebugFlags.App.EnableShadows) {
+            setTranslationZ(0f);
+        }
         setScaleX(1f);
         setScaleY(1f);
         setAlpha(1f);
@@ -213,8 +225,8 @@
         mBarView.setAlpha(0f);
         mBarView.animate()
                 .alpha(1f)
-                .setStartDelay(235)
-                .setInterpolator(BakedBezierInterpolator.INSTANCE)
+                .setStartDelay(250)
+                .setInterpolator(config.defaultBezierInterpolator)
                 .setDuration(config.taskBarEnterAnimDuration)
                 .withLayer()
                 .start();
@@ -226,7 +238,7 @@
         mBarView.animate()
             .alpha(0f)
             .setStartDelay(0)
-            .setInterpolator(BakedBezierInterpolator.INSTANCE)
+            .setInterpolator(config.defaultBezierInterpolator)
             .setDuration(config.taskBarExitAnimDuration)
             .withLayer()
             .withEndAction(new Runnable() {
@@ -238,6 +250,24 @@
             .start();
     }
 
+    /** Animates the deletion of this task view */
+    public void animateRemoval(final Runnable r) {
+        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        animate().translationX(config.taskViewRemoveAnimTranslationXPx)
+            .alpha(0f)
+            .setStartDelay(0)
+            .setInterpolator(config.defaultBezierInterpolator)
+            .setDuration(config.taskViewRemoveAnimDuration)
+            .withLayer()
+            .withEndAction(new Runnable() {
+                @Override
+                public void run() {
+                    post(r);
+                }
+            })
+            .start();
+    }
+
     /** Returns the rect we want to clip (it may not be the full rect) */
     Rect getClippingRect(Rect outRect) {
         getHitRect(outRect);
@@ -284,7 +314,7 @@
         mInfoView.animate()
                 .alpha(0f)
                 .setDuration(config.taskViewInfoPaneAnimDuration)
-                .setInterpolator(BakedBezierInterpolator.INSTANCE)
+                .setInterpolator(config.defaultBezierInterpolator)
                 .withLayer()
                 .withEndAction(new Runnable() {
                     @Override
@@ -354,6 +384,7 @@
             mInfoView.rebindToTask(mTask, reloadingTaskData);
             // Rebind any listeners
             mBarView.mApplicationIcon.setOnClickListener(this);
+            mBarView.mDismissButton.setOnClickListener(this);
             mInfoView.mAppInfoButton.setOnClickListener(this);
         }
         mTaskDataLoaded = true;
@@ -379,6 +410,15 @@
             hideInfoPane();
         } else if (v == mBarView.mApplicationIcon) {
             mCb.onTaskIconClicked(this);
+        } else if (v == mBarView.mDismissButton) {
+            // Animate out the view and call the callback
+            final TaskView tv = this;
+            animateRemoval(new Runnable() {
+                @Override
+                public void run() {
+                    mCb.onTaskDismissed(tv);
+                }
+            });
         } else if (v == mInfoView.mAppInfoButton) {
             mCb.onTaskAppInfoClicked(this);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index 0748bbb..e6391a8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -24,6 +24,7 @@
     public int translationY = 0;
     public float scale = 1f;
     public float alpha = 1f;
+    public float dismissAlpha = 1f;
     public boolean visible = false;
     public Rect rect = new Rect();
     float t;
@@ -36,6 +37,7 @@
         translationY = o.translationY;
         scale = o.scale;
         alpha = o.alpha;
+        dismissAlpha = o.dismissAlpha;
         visible = o.visible;
         rect.set(o.rect);
         t = o.t;
@@ -44,6 +46,6 @@
     @Override
     public String toString() {
         return "TaskViewTransform y: " + translationY + " scale: " + scale + " alpha: " + alpha +
-                " visible: " + visible + " rect: " + rect;
+                " visible: " + visible + " rect: " + rect + " dismissAlpha: " + dismissAlpha;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 1c88ea7..91df9ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -38,6 +38,7 @@
 public abstract class ActivatableNotificationView extends ExpandableOutlineView {
 
     private static final long DOUBLETAP_TIMEOUT_MS = 1000;
+    private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220;
 
     private boolean mDimmed;
 
@@ -174,12 +175,14 @@
     private void makeInactive() {
         if (mActivated) {
             // Make sure that we clear the hotspot from the center.
-            mBackgroundDimmed.setHotspot(0, getWidth() / 2, getActualHeight() / 2);
-            mBackgroundDimmed.removeHotspot(0);
+            if (mBackgroundDimmed != null) {
+                mBackgroundDimmed.setHotspot(0, getWidth() / 2, getActualHeight() / 2);
+                mBackgroundDimmed.removeHotspot(0);
+            }
             mActivated = false;
         }
         if (mOnActivatedListener != null) {
-            mOnActivatedListener.onReset(this);
+            mOnActivatedListener.onActivationReset(this);
         }
         removeCallbacks(mTapTimeoutRunnable);
     }
@@ -189,12 +192,6 @@
                 && Math.abs(event.getY() - mDownY) < mTouchSlop;
     }
 
-    /**
-     * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
-     *
-     * @param dimmed Whether the notification should be dimmed.
-     * @param fade Whether an animation should be played to change the state.
-     */
     public void setDimmed(boolean dimmed, boolean fade) {
         if (mDimmed != dimmed) {
             mDimmed = dimmed;
@@ -226,7 +223,7 @@
         }
         int startAlpha = mDimmed ? 255 : 0;
         int endAlpha = mDimmed ? 0 : 255;
-        int duration = NotificationActivator.ANIMATION_LENGTH_MS;
+        int duration = BACKGROUND_ANIMATION_LENGTH_MS;
         // Check whether there is already a background animation running.
         if (mBackgroundAnimator != null) {
             startAlpha = (Integer) mBackgroundAnimator.getAnimatedValue();
@@ -313,8 +310,8 @@
     }
 
     @Override
-    public void setActualHeight(int actualHeight) {
-        super.setActualHeight(actualHeight);
+    public void setActualHeight(int actualHeight, boolean notifyListeners) {
+        super.setActualHeight(actualHeight, notifyListeners);
         invalidate();
         setPivotY(actualHeight / 2);
     }
@@ -331,6 +328,6 @@
 
     public interface OnActivatedListener {
         void onActivated(View view);
-        void onReset(View view);
+        void onActivationReset(View view);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index d224975..898f06e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -70,7 +70,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarIconList;
-import com.android.internal.util.LegacyNotificationUtil;
+import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SearchPanelView;
@@ -143,7 +143,7 @@
     // public mode, private notifications, etc
     private boolean mLockscreenPublicMode = false;
     private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
-    private LegacyNotificationUtil mLegacyNotificationUtil = LegacyNotificationUtil.getInstance();
+    private NotificationColorUtil mNotificationColorUtil = NotificationColorUtil.getInstance();
 
     private UserManager mUserManager;
 
@@ -852,7 +852,7 @@
 
             Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic);
             icon.setImageDrawable(iconDrawable);
-            if (mLegacyNotificationUtil.isGrayscale(iconDrawable)) {
+            if (mNotificationColorUtil.isGrayscale(iconDrawable)) {
                 icon.setBackgroundResource(
                         com.android.internal.R.drawable.notification_icon_legacy_bg_inset);
             }
@@ -1029,6 +1029,9 @@
     }
 
     protected void addNotificationViews(NotificationData.Entry entry) {
+        if (entry == null) {
+            return;
+        }
         // Add the expanded view and icon.
         int pos = mNotificationData.add(entry);
         if (DEBUG) {
@@ -1067,7 +1070,6 @@
                     entry.row.setSystemExpanded(top);
                 }
             }
-            entry.row.setDimmed(onKeyguard, false /* fade */);
             boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
             if (onKeyguard && (visibleNotifications >= maxKeyguardNotifications
                     || !showOnKeyguard)) {
@@ -1087,48 +1089,11 @@
 
         if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
             mKeyguardIconOverflowContainer.setVisibility(View.VISIBLE);
-            mKeyguardIconOverflowContainer.setDimmed(true /* dimmed */, false /* fade */);
         } else {
             mKeyguardIconOverflowContainer.setVisibility(View.GONE);
         }
     }
 
-    @Override
-    public void onActivated(View view) {
-        int n = mNotificationData.size();
-        for (int i = 0; i < n; i++) {
-            NotificationData.Entry entry = mNotificationData.get(i);
-            if (entry.row.getVisibility() != View.GONE) {
-                if (view == entry.row) {
-                    entry.row.getActivator().activate();
-                } else {
-                    entry.row.getActivator().activateInverse();
-                }
-            }
-        }
-        if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
-            if (view == mKeyguardIconOverflowContainer) {
-                mKeyguardIconOverflowContainer.getActivator().activate();
-            } else {
-                mKeyguardIconOverflowContainer.getActivator().activateInverse();
-            }
-        }
-    }
-
-    @Override
-    public void onReset(View view) {
-        int n = mNotificationData.size();
-        for (int i = 0; i < n; i++) {
-            NotificationData.Entry entry = mNotificationData.get(i);
-            if (entry.row.getVisibility() != View.GONE) {
-                entry.row.getActivator().reset();
-            }
-        }
-        if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
-            mKeyguardIconOverflowContainer.getActivator().reset();
-        }
-    }
-
     private boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
         return sbn.getNotification().priority >= Notification.PRIORITY_LOW;
     }
@@ -1144,7 +1109,6 @@
     protected abstract void updateNotificationIcons();
     protected abstract void tick(IBinder key, StatusBarNotification n, boolean firstTime);
     protected abstract void updateExpandedViewPos(int expandedPosition);
-    protected abstract int getExpandedViewMaxHeight();
     protected abstract boolean shouldDisableNavbarGestures();
 
     protected boolean isTopNotification(ViewGroup parent, NotificationData.Entry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index e471754..5b2ea0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -117,7 +117,7 @@
                 } else {
                     if (mDraggedFarEnough) {
                         mDraggedFarEnough = false;
-                        mOnDragDownListener.onReset();
+                        mOnDragDownListener.onDragDownReset();
                     }
                 }
                 return true;
@@ -188,7 +188,7 @@
             cancelExpansion(mStartingChild);
         }
         mDraggingDown = false;
-        mOnDragDownListener.onReset();
+        mOnDragDownListener.onDragDownReset();
     }
 
     private ExpandableView findView(float x, float y) {
@@ -200,7 +200,7 @@
 
     public interface OnDragDownListener {
         void onDraggedDown(View startingChild);
-        void onReset();
+        void onDragDownReset();
         void onThresholdReached();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index e5512a3..39f2bb9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -52,7 +52,6 @@
     private NotificationContentView mPublicLayout;
     private NotificationContentView mPrivateLayout;
     private int mMaxExpandHeight;
-    private NotificationActivator mActivator;
 
     public ExpandableNotificationRow(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -63,8 +62,6 @@
         super.onFinishInflate();
         mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
         mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
-
-        mActivator = new NotificationActivator(this, this);
     }
 
     @Override
@@ -208,23 +205,10 @@
         mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE);
     }
 
-    /**
-     * Sets the notification as dimmed, meaning that it will appear in a more gray variant.
-     */
-    @Override
-    public void setDimmed(boolean dimmed, boolean fade) {
-        super.setDimmed(dimmed, fade);
-        mActivator.setDimmed(dimmed, fade);
-    }
-
     public int getMaxExpandHeight() {
         return mMaxExpandHeight;
     }
 
-    public NotificationActivator getActivator() {
-        return mActivator;
-    }
-
     /**
      * @return the potential height this view could expand in addition.
      */
@@ -238,10 +222,10 @@
     }
 
     @Override
-    public void setActualHeight(int height) {
-        mPrivateLayout.setActualHeight(height);
+    public void setActualHeight(int height, boolean notifyListeners) {
+        mPrivateLayout.setActualHeight(height, notifyListeners);
         invalidate();
-        super.setActualHeight(height);
+        super.setActualHeight(height, notifyListeners);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 43eb5b5..a42c194 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -33,8 +33,8 @@
     }
 
     @Override
-    public void setActualHeight(int actualHeight) {
-        super.setActualHeight(actualHeight);
+    public void setActualHeight(int actualHeight, boolean notifyListeners) {
+        super.setActualHeight(actualHeight, notifyListeners);
         updateOutline();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 169521d..281bd2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -61,10 +61,19 @@
     /**
      * Sets the actual height of this notification. This is different than the laid out
      * {@link View#getHeight()}, as we want to avoid layouting during scrolling and expanding.
+     *
+     * @param actualHeight The height of this notification.
+     * @param notifyListeners Whether the listener should be informed about the change.
      */
-    public void setActualHeight(int actualHeight) {
+    public void setActualHeight(int actualHeight, boolean notifyListeners) {
         mActualHeight = actualHeight;
-        notifyHeightChanged();
+        if (notifyListeners) {
+            notifyHeightChanged();
+        }
+    }
+
+    public void setActualHeight(int actualHeight) {
+        setActualHeight(actualHeight, true);
     }
 
     /**
@@ -91,6 +100,15 @@
     }
 
     /**
+     * Sets the notification as dimmed. The default implementation does nothing.
+     *
+     * @param dimmed Whether the notification should be dimmed.
+     * @param fade Whether an animation should be played to change the state.
+     */
+    public void setDimmed(boolean dimmed, boolean fade) {
+    }
+
+    /**
      * @return The desired notification height.
      */
     public int getIntrinsicHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
deleted file mode 100644
index a03aeec..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
+++ /dev/null
@@ -1,152 +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.statusbar;
-
-import android.content.Context;
-import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import com.android.systemui.R;
-
-/**
- * A helper class used by both {@link com.android.systemui.statusbar.ExpandableNotificationRow} and
- * {@link com.android.systemui.statusbar.NotificationOverflowIconsView} to make a notification look
- * active after tapping it once on the Keyguard.
- */
-public class NotificationActivator {
-
-    public static final int ANIMATION_LENGTH_MS = 220;
-    private static final float INVERSE_ALPHA = 0.9f;
-    private static final float DIMMED_SCALE = 0.95f;
-
-    /**
-     * Normal state. Notification is fully interactable.
-     */
-    private static final int STATE_NORMAL = 0;
-
-    /**
-     * Dimmed state. Neutral state when on the lockscreen, with slight transparency and scaled down
-     * a bit.
-     */
-    private static final int STATE_DIMMED = 1;
-
-    /**
-     * Activated state. Used after tapping a notification on the lockscreen. Normal transparency and
-     * normal scale.
-     */
-    private static final int STATE_ACTIVATED = 2;
-
-    /**
-     * Inverse activated state. Used for the other notifications on the lockscreen when tapping on
-     * one.
-     */
-    private static final int STATE_ACTIVATED_INVERSE = 3;
-
-    private final View mTargetView;
-    private final View mHotspotView;
-    private final Interpolator mFastOutSlowInInterpolator;
-    private final Interpolator mLinearOutSlowInInterpolator;
-    private final int mTranslationZ;
-
-    private int mState;
-
-    public NotificationActivator(View targetView, View hotspotView) {
-        mTargetView = targetView;
-        mHotspotView = hotspotView;
-        Context ctx = targetView.getContext();
-        mFastOutSlowInInterpolator =
-                AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in);
-        mLinearOutSlowInInterpolator =
-                AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in);
-        mTranslationZ =
-                ctx.getResources().getDimensionPixelSize(R.dimen.z_distance_between_notifications);
-        mTargetView.animate().setDuration(ANIMATION_LENGTH_MS);
-    }
-
-    public void activateInverse() {
-        if (mState == STATE_ACTIVATED_INVERSE) {
-            return;
-        }
-        mTargetView.animate().cancel();
-        mTargetView.animate().withLayer().alpha(INVERSE_ALPHA);
-        mState = STATE_ACTIVATED_INVERSE;
-    }
-
-    public void addHotspot() {
-        mHotspotView.getBackground().setHotspot(
-                0, mHotspotView.getWidth()/2, mHotspotView.getHeight()/2);
-    }
-
-    public void activate() {
-        if (mState == STATE_ACTIVATED) {
-            return;
-        }
-        mTargetView.animate().cancel();
-        mTargetView.animate()
-                .setInterpolator(mLinearOutSlowInInterpolator)
-                .scaleX(1)
-                .scaleY(1)
-                .translationZBy(mTranslationZ);
-        mState = STATE_ACTIVATED;
-    }
-
-    public void reset() {
-        if (mState == STATE_DIMMED) {
-            return;
-        }
-        mTargetView.animate().cancel();
-        mTargetView.animate()
-                .setInterpolator(mFastOutSlowInInterpolator)
-                .scaleX(DIMMED_SCALE)
-                .scaleY(DIMMED_SCALE)
-                .translationZBy(-mTranslationZ);
-        if (mTargetView.getAlpha() != 1.0f) {
-            mTargetView.animate().withLayer().alpha(1);
-        }
-        mState = STATE_DIMMED;
-    }
-
-    public void setDimmed(boolean dimmed, boolean fade) {
-        if (dimmed) {
-            mTargetView.animate().cancel();
-            if (fade) {
-                mTargetView.animate()
-                        .setInterpolator(mFastOutSlowInInterpolator)
-                        .scaleX(DIMMED_SCALE)
-                        .scaleY(DIMMED_SCALE);
-            } else {
-                mTargetView.setScaleX(DIMMED_SCALE);
-                mTargetView.setScaleY(DIMMED_SCALE);
-            }
-            mState = STATE_DIMMED;
-        } else {
-            mTargetView.animate().cancel();
-            if (fade) {
-                mTargetView.animate()
-                        .setInterpolator(mFastOutSlowInInterpolator)
-                        .scaleX(1)
-                        .scaleY(1);
-            } else {
-                mTargetView.animate().cancel();
-                mTargetView.setScaleX(1);
-                mTargetView.setScaleY(1);
-            }
-            mState = STATE_NORMAL;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 379bd05..9df2701 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -70,8 +70,8 @@
     }
 
     @Override
-    public void setActualHeight(int actualHeight) {
-        super.setActualHeight(actualHeight);
+    public void setActualHeight(int actualHeight, boolean notifyListeners) {
+        super.setActualHeight(actualHeight, notifyListeners);
         selectLayout();
         updateClipping();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index e6b5600..864c597 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -28,14 +28,13 @@
 public class NotificationOverflowContainer extends ActivatableNotificationView {
 
     private NotificationOverflowIconsView mIconsView;
-    private NotificationActivator mActivator;
 
     public NotificationOverflowContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
     @Override
-    public void setActualHeight(int currentHeight) {
+    public void setActualHeight(int currentHeight, boolean notifyListeners) {
         // noop
     }
 
@@ -54,22 +53,9 @@
         super.onFinishInflate();
         mIconsView = (NotificationOverflowIconsView) findViewById(R.id.overflow_icons_view);
         mIconsView.setMoreText((TextView) findViewById(R.id.more_text));
-
-        mActivator = new NotificationActivator(this, this);
-        setDimmed(true, false);
-    }
-
-    @Override
-    public void setDimmed(boolean dimmed, boolean fade) {
-        super.setDimmed(dimmed, fade);
-        mActivator.setDimmed(dimmed, fade);
     }
 
     public NotificationOverflowIconsView getIconsView() {
         return mIconsView;
     }
-
-    public NotificationActivator getActivator() {
-        return mActivator;
-    }
 }
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 627b80f..c74911f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -16,11 +16,19 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
+import android.view.VelocityTracker;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.LinearLayout;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableView;
@@ -29,18 +37,40 @@
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 public class NotificationPanelView extends PanelView implements
-        ExpandableView.OnHeightChangedListener {
+        ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
+        View.OnClickListener {
     public static final boolean DEBUG_GESTURES = true;
+    private static final int EXPANSION_ANIMATION_LENGTH = 375;
 
     PhoneStatusBar mStatusBar;
-    private View mHeader;
+    private StatusBarHeaderView mHeader;
+    private QuickSettingsContainerView mQsContainer;
     private View mKeyguardStatusView;
+    private ObservableScrollView mScrollView;
+    private View mStackScrollerContainer;
 
     private NotificationStackScrollLayout mNotificationStackScroller;
-    private boolean mTrackingSettings;
     private int mNotificationTopPadding;
     private boolean mAnimateNextTopPaddingChange;
 
+    private Interpolator mExpansionInterpolator;
+
+    private int mTrackingPointer;
+    private VelocityTracker mVelocityTracker;
+    private boolean mTracking;
+    private boolean mQsExpanded;
+    private float mInitialHeightOnTouch;
+    private float mInitialTouchX;
+    private float mInitialTouchY;
+    private float mQsExpansionHeight;
+    private int mQsMinExpansionHeight;
+    private int mQsMaxExpansionHeight;
+    private int mMinStackHeight;
+    private float mNotificationTranslation;
+    private int mStackScrollerIntrinsicPadding;
+    private boolean mQsExpansionEnabled = true;
+    private ValueAnimator mQsExpansionAnimator;
+
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -63,14 +93,21 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-
-        mHeader = findViewById(R.id.header);
+        mHeader = (StatusBarHeaderView) findViewById(R.id.header);
+        mHeader.getBackgroundView().setOnClickListener(this);
         mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
+        mStackScrollerContainer = findViewById(R.id.notification_container_parent);
+        mQsContainer = (QuickSettingsContainerView) findViewById(R.id.quick_settings_container);
+        mScrollView = (ObservableScrollView) findViewById(R.id.scroll_view);
+        mScrollView.setListener(this);
         mNotificationStackScroller = (NotificationStackScrollLayout)
                 findViewById(R.id.notification_stack_scroller);
         mNotificationStackScroller.setOnHeightChangedListener(this);
         mNotificationTopPadding = getResources().getDimensionPixelSize(
                 R.dimen.notifications_top_padding);
+        mMinStackHeight = getResources().getDimensionPixelSize(R.dimen.collapsed_stack_height);
+        mExpansionInterpolator = AnimationUtils.loadInterpolator(
+                getContext(), android.R.interpolator.fast_out_slow_in);
     }
 
     @Override
@@ -78,11 +115,21 @@
         super.onLayout(changed, left, top, right, bottom);
         int keyguardBottomMargin =
                 ((MarginLayoutParams) mKeyguardStatusView.getLayoutParams()).bottomMargin;
-        mNotificationStackScroller.setTopPadding(mStatusBar.getBarState() == StatusBarState.KEYGUARD
-                ? mKeyguardStatusView.getBottom() + keyguardBottomMargin
-                : mHeader.getBottom() + mNotificationTopPadding,
-                mAnimateNextTopPaddingChange);
-        mAnimateNextTopPaddingChange = false;
+        if (!mQsExpanded) {
+            mStackScrollerIntrinsicPadding = mStatusBar.getBarState() == StatusBarState.KEYGUARD
+                    ? mKeyguardStatusView.getBottom() + keyguardBottomMargin
+                    : mHeader.getBottom() + mNotificationTopPadding;
+            mNotificationStackScroller.setTopPadding(mStackScrollerIntrinsicPadding,
+                    mAnimateNextTopPaddingChange);
+            mAnimateNextTopPaddingChange = false;
+        }
+
+        // Calculate quick setting heights.
+        mQsMinExpansionHeight = mHeader.getCollapsedHeight();
+        mQsMaxExpansionHeight = mHeader.getExpandedHeight() + mQsContainer.getHeight();
+        if (mQsExpansionHeight == 0) {
+            mQsExpansionHeight = mQsMinExpansionHeight;
+        }
     }
 
     public void animateNextTopPaddingChange() {
@@ -90,6 +137,29 @@
         requestLayout();
     }
 
+    /**
+     * @return Whether Quick Settings are currently expanded.
+     */
+    public boolean isQsExpanded() {
+        return mQsExpanded;
+    }
+
+    public void setQsExpansionEnabled(boolean qsExpansionEnabled) {
+        mQsExpansionEnabled = qsExpansionEnabled;
+    }
+
+    public void closeQs() {
+        cancelAnimation();
+        setQsExpansion(mQsMinExpansionHeight);
+    }
+
+    public void openQs() {
+        cancelAnimation();
+        if (mQsExpansionEnabled) {
+            setQsExpansion(mQsMaxExpansionHeight);
+        }
+    }
+
     @Override
     public void fling(float vel, boolean always) {
         GestureRecorder gr = ((PhoneStatusBarView) mBar).mBar.getGestureRecorder();
@@ -114,42 +184,273 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        // intercept for quick settings
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            final View target = mStatusBar.getBarState() == StatusBarState.KEYGUARD
-                    ? mKeyguardStatusView
-                    : mHeader;
-            final boolean inTarget = PhoneStatusBar.inBounds(target, event, true);
-            if (inTarget && !isInSettings()) {
-                mTrackingSettings = true;
-                requestDisallowInterceptTouchEvent(true);
-                return true;
-            }
-            if (!inTarget && isInSettings()) {
-                mTrackingSettings = true;
-                requestDisallowInterceptTouchEvent(true);
-                return true;
-            }
+        int pointerIndex = event.findPointerIndex(mTrackingPointer);
+        if (pointerIndex < 0) {
+            pointerIndex = 0;
+            mTrackingPointer = event.getPointerId(pointerIndex);
         }
-        return super.onInterceptTouchEvent(event);
+        final float x = event.getX(pointerIndex);
+        final float y = event.getY(pointerIndex);
+
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                mInitialTouchY = y;
+                mInitialTouchX = x;
+                initVelocityTracker();
+                trackMovement(event);
+                if (shouldIntercept(mInitialTouchX, mInitialTouchY, 0)) {
+                    getParent().requestDisallowInterceptTouchEvent(true);
+                }
+                break;
+            case MotionEvent.ACTION_POINTER_UP:
+                final int upPointer = event.getPointerId(event.getActionIndex());
+                if (mTrackingPointer == upPointer) {
+                    // gesture is ongoing, find a new pointer to track
+                    final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+                    mTrackingPointer = event.getPointerId(newIndex);
+                    mInitialTouchX = event.getX(newIndex);
+                    mInitialTouchY = event.getY(newIndex);
+                }
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                final float h = y - mInitialTouchY;
+                trackMovement(event);
+                if (Math.abs(h) > mTouchSlop && Math.abs(h) > Math.abs(x - mInitialTouchX)
+                        && shouldIntercept(mInitialTouchX, mInitialTouchY, h)) {
+                    onQsExpansionStarted();
+                    mInitialHeightOnTouch = mQsExpansionHeight;
+                    mInitialTouchY = y;
+                    mInitialTouchX = x;
+                    mTracking = true;
+                    return true;
+                }
+                break;
+        }
+        return !mQsExpanded && super.onInterceptTouchEvent(event);
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         // TODO: Handle doublefinger swipe to notifications again. Look at history for a reference
         // implementation.
-        if (mTrackingSettings) {
-            mStatusBar.onSettingsEvent(event);
-            if (event.getAction() == MotionEvent.ACTION_UP
-                    || event.getAction() == MotionEvent.ACTION_CANCEL) {
-                mTrackingSettings = false;
+        if (mTracking) {
+            int pointerIndex = event.findPointerIndex(mTrackingPointer);
+            if (pointerIndex < 0) {
+                pointerIndex = 0;
+                mTrackingPointer = event.getPointerId(pointerIndex);
+            }
+            final float y = event.getY(pointerIndex);
+            final float x = event.getX(pointerIndex);
+
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                    mTracking = true;
+                    mInitialTouchY = y;
+                    mInitialTouchX = x;
+                    onQsExpansionStarted();
+                    mInitialHeightOnTouch = mQsExpansionHeight;
+                    initVelocityTracker();
+                    trackMovement(event);
+                    break;
+
+                case MotionEvent.ACTION_POINTER_UP:
+                    final int upPointer = event.getPointerId(event.getActionIndex());
+                    if (mTrackingPointer == upPointer) {
+                        // gesture is ongoing, find a new pointer to track
+                        final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+                        final float newY = event.getY(newIndex);
+                        final float newX = event.getX(newIndex);
+                        mTrackingPointer = event.getPointerId(newIndex);
+                        mInitialHeightOnTouch = mQsExpansionHeight;
+                        mInitialTouchY = newY;
+                        mInitialTouchX = newX;
+                    }
+                    break;
+
+                case MotionEvent.ACTION_MOVE:
+                    final float h = y - mInitialTouchY;
+                    setQsExpansion(h + mInitialHeightOnTouch);
+                    trackMovement(event);
+                    break;
+
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_CANCEL:
+                    mTracking = false;
+                    mTrackingPointer = -1;
+                    trackMovement(event);
+
+                    float vel = getCurrentVelocity();
+
+                    // TODO: Better logic whether we should expand or not.
+                    flingSettings(vel, vel > 0);
+
+                    if (mVelocityTracker != null) {
+                        mVelocityTracker.recycle();
+                        mVelocityTracker = null;
+                    }
+                    break;
             }
             return true;
         }
-        if (isInSettings()) {
-            return true;
+
+        // Consume touch events when QS are expanded.
+        return mQsExpanded || super.onTouchEvent(event);
+    }
+
+    private void onQsExpansionStarted() {
+        cancelAnimation();
+
+        // Reset scroll position and apply that position to the expanded height.
+        float height = mQsExpansionHeight - mScrollView.getScrollY();
+        mScrollView.scrollTo(0, 0);
+        setQsExpansion(height);
+    }
+
+    private void expandQs() {
+        mHeader.setExpanded(true);
+        mNotificationStackScroller.setEnabled(false);
+        mScrollView.setVisibility(View.VISIBLE);
+        mQsExpanded = true;
+    }
+
+    private void collapseQs() {
+        mHeader.setExpanded(false);
+        mNotificationStackScroller.setEnabled(true);
+        mScrollView.setVisibility(View.INVISIBLE);
+        mQsExpanded = false;
+    }
+
+    private void setQsExpansion(float height) {
+        height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight);
+        if (height > mQsMinExpansionHeight && !mQsExpanded) {
+            expandQs();
+        } else if (height <= mQsMinExpansionHeight && mQsExpanded) {
+            collapseQs();
         }
-        return super.onTouchEvent(event);
+        mQsExpansionHeight = height;
+        mHeader.setExpansion(height);
+        setQsTranslation(height);
+        setQsStackScrollerPadding(height);
+    }
+
+    private void setQsTranslation(float height) {
+        mQsContainer.setY(height - mQsContainer.getHeight());
+    }
+
+    private void setQsStackScrollerPadding(float height) {
+        float start = height - mScrollView.getScrollY() + mNotificationTopPadding;
+        float stackHeight = mNotificationStackScroller.getHeight() - start;
+        if (stackHeight <= mMinStackHeight) {
+            float overflow = mMinStackHeight - stackHeight;
+            stackHeight = mMinStackHeight;
+            start = mNotificationStackScroller.getHeight() - stackHeight;
+            mNotificationStackScroller.setTranslationY(overflow);
+            mNotificationTranslation = overflow + mScrollView.getScrollY();
+        } else {
+            mNotificationStackScroller.setTranslationY(0);
+            mNotificationTranslation = mScrollView.getScrollY();
+        }
+        mNotificationStackScroller.setTopPadding(clampQsStackScrollerPadding((int) start), false);
+    }
+
+    private int clampQsStackScrollerPadding(int desiredPadding) {
+        return Math.max(desiredPadding, mStackScrollerIntrinsicPadding);
+    }
+
+    private void trackMovement(MotionEvent event) {
+        if (mVelocityTracker != null) mVelocityTracker.addMovement(event);
+    }
+
+    private void initVelocityTracker() {
+        if (mVelocityTracker != null) {
+            mVelocityTracker.recycle();
+        }
+        mVelocityTracker = VelocityTracker.obtain();
+    }
+
+    private float getCurrentVelocity() {
+        if (mVelocityTracker == null) {
+            return 0;
+        }
+        mVelocityTracker.computeCurrentVelocity(1000);
+        return mVelocityTracker.getYVelocity();
+    }
+
+    private void cancelAnimation() {
+        if (mQsExpansionAnimator != null) {
+            mQsExpansionAnimator.cancel();
+        }
+    }
+    private void flingSettings(float vel, boolean expand) {
+
+        // TODO: Actually use velocity.
+
+        float target = expand ? mQsMaxExpansionHeight : mQsMinExpansionHeight;
+        ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
+        animator.setDuration(EXPANSION_ANIMATION_LENGTH);
+        animator.setInterpolator(mExpansionInterpolator);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                setQsExpansion((Float) animation.getAnimatedValue());
+            }
+        });
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mQsExpansionAnimator = null;
+            }
+        });
+        animator.start();
+        mQsExpansionAnimator = animator;
+    }
+
+    /**
+     * @return Whether we should intercept a gesture to open Quick Settings.
+     */
+    private boolean shouldIntercept(float x, float y, float yDiff) {
+        if (!mQsExpansionEnabled) {
+            return false;
+        }
+        View headerView = mStatusBar.getBarState() == StatusBarState.KEYGUARD && !mQsExpanded
+                ? mKeyguardStatusView
+                : mHeader;
+        boolean onHeader = x >= headerView.getLeft() && x <= headerView.getRight()
+                && y >= headerView.getTop() && y <= headerView.getBottom();
+        if (mQsExpanded) {
+            return onHeader || (mScrollView.isScrolledToBottom() && yDiff < 0);
+        } else {
+            return onHeader;
+        }
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        int oldVisibility = getVisibility();
+        super.setVisibility(visibility);
+        if (visibility != oldVisibility) {
+            reparentStatusIcons(visibility == VISIBLE);
+        }
+    }
+
+    /**
+     * When the notification panel gets expanded, we need to move the status icons in the header
+     * card.
+     */
+    private void reparentStatusIcons(boolean toHeader) {
+        if (mStatusBar == null) {
+            return;
+        }
+        LinearLayout systemIcons = mStatusBar.getSystemIcons();
+        if (systemIcons.getParent() != null) {
+            ((ViewGroup) systemIcons.getParent()).removeView(systemIcons);
+        }
+        if (toHeader) {
+            mHeader.attachSystemIcons(systemIcons);
+        } else {
+            mStatusBar.reattachSystemIcons();
+        }
     }
 
     @Override
@@ -164,14 +465,16 @@
     protected int getMaxPanelHeight() {
         if (!isInSettings()) {
             int maxPanelHeight = super.getMaxPanelHeight();
-            int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
+            int notificationMarginBottom = mStackScrollerContainer.getPaddingBottom();
+            int emptyBottomMargin = notificationMarginBottom
+                    + mNotificationStackScroller.getEmptyBottomMargin();
             return maxPanelHeight - emptyBottomMargin;
         }
         return super.getMaxPanelHeight();
     }
 
     private boolean isInSettings() {
-        return mStatusBar != null && mStatusBar.isFlippedToSettings();
+        return mQsExpanded;
     }
 
     @Override
@@ -200,4 +503,24 @@
     public void onHeightChanged(ExpandableView view) {
         requestPanelHeightUpdate();
     }
+
+    @Override
+    public void onScrollChanged() {
+        if (mQsExpanded) {
+            mNotificationStackScroller.setTranslationY(
+                    mNotificationTranslation - mScrollView.getScrollY());
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mHeader.getBackgroundView()) {
+            onQsExpansionStarted();
+            if (mQsExpanded) {
+                flingSettings(0 /* vel */, false /* expand */);
+            } else if (mQsExpansionEnabled) {
+                flingSettings(0 /* vel */, true /* expand */);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
new file mode 100644
index 0000000..f41e78d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.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 com.android.systemui.statusbar.phone;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+/**
+ * The container with notification stack scroller and quick settings inside.
+ */
+public class NotificationsQuickSettingsContainer extends FrameLayout {
+
+    public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected boolean fitSystemWindows(Rect insets) {
+        setPadding(0, 0, 0, insets.bottom);
+        insets.bottom = 0;
+        return true;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
new file mode 100644
index 0000000..46484f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ObservableScrollView.java
@@ -0,0 +1,64 @@
+/*
+ * 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.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ScrollView;
+
+/**
+ * A scroll view which can be observed for scroll change events.
+ */
+public class ObservableScrollView extends ScrollView {
+
+    private Listener mListener;
+
+    public ObservableScrollView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void setListener(Listener listener) {
+        mListener = listener;
+    }
+
+    public boolean isScrolledToBottom() {
+        return getScrollY() == getMaxScrollY();
+    }
+
+    private int getMaxScrollY() {
+        int scrollRange = 0;
+        if (getChildCount() > 0) {
+            View child = getChildAt(0);
+            scrollRange = Math.max(0,
+                    child.getHeight() - (getHeight() - mPaddingBottom - mPaddingTop));
+        }
+        return scrollRange;
+    }
+
+    @Override
+    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+        super.onScrollChanged(l, t, oldl, oldt);
+        if (mListener != null) {
+            mListener.onScrollChanged();
+        }
+    }
+
+    public interface Listener {
+        void onScrollChanged();
+    }
+}
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 a853b2a..8c70517 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -75,7 +75,7 @@
     private boolean mClosing;
     private boolean mTracking;
     private int mTrackingPointer;
-    private int mTouchSlop;
+    protected int mTouchSlop;
 
     private TimeAnimator mTimeAnimator;
     private ObjectAnimator mPeekAnimator;
@@ -220,9 +220,9 @@
     private float mVel, mAccel;
     protected int mMaxPanelHeight = 0;
     private String mViewName;
-    protected float mInitialTouchY;
-    protected float mInitialTouchX;
-    protected float mFinalTouchY;
+    private float mInitialTouchY;
+    private float mInitialTouchX;
+    private float mFinalTouchY;
 
     protected void onExpandingFinished() {
     }
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 3856ba1..dad858e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -29,7 +29,6 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -73,7 +72,6 @@
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ViewPropertyAnimator;
@@ -192,8 +190,6 @@
     int mIconHPadding = -1;
     Display mDisplay;
     Point mCurrentDisplaySize = new Point();
-    private float mHeadsUpVerticalOffset;
-    private int[] mStackScrollerPosition = new int[2];
 
     StatusBarWindowView mStatusBarWindow;
     PhoneStatusBarView mStatusBarView;
@@ -208,6 +204,7 @@
 
     // right-hand icons
     LinearLayout mSystemIconArea;
+    LinearLayout mSystemIcons;
 
     // left-hand icons
     LinearLayout mStatusIcons;
@@ -222,19 +219,18 @@
     NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
     View mExpandedContents;
     int mNotificationPanelGravity;
-    int mNotificationPanelMarginBottomPx, mNotificationPanelMarginPx;
+    int mNotificationPanelMarginBottomPx;
     float mNotificationPanelMinHeightFrac;
     boolean mNotificationPanelIsFullScreenWidth;
     TextView mNotificationPanelDebugText;
 
     // settings
     QuickSettings mQS;
-    boolean mHasQuickSettings;
     View mFlipSettingsView;
     QuickSettingsContainerView mSettingsContainer;
 
     // top bar
-    View mNotificationPanelHeader;
+    StatusBarHeaderView mHeader;
     View mKeyguardStatusView;
     KeyguardBottomAreaView mKeyguardBottomArea;
     boolean mLeaveOpenOnKeyguardHide;
@@ -244,16 +240,13 @@
     String mKeyguardHotwordPhrase = "";
     int mKeyguardMaxNotificationCount;
     View mDateTimeView;
-    View mClearButton;
-    FlipperButton mHeaderFlipper, mKeyguardFlipper;
 
     // carrier/wifi label
     private TextView mCarrierLabel;
     private boolean mCarrierLabelVisible = false;
     private int mCarrierLabelHeight;
     private TextView mEmergencyCallLabel;
-    private int mNotificationHeaderHeight;
-    private View mKeyguardCarrierLabel;
+    private int mStatusBarHeaderHeight;
 
     private boolean mShowCarrierInPanel = false;
 
@@ -326,11 +319,12 @@
             if (MULTIUSER_DEBUG) Log.d(TAG, String.format("User setup changed: " +
                     "selfChange=%s userSetup=%s mUserSetup=%s",
                     selfChange, userSetup, mUserSetup));
-            mHeaderFlipper.userSetup(userSetup);
-            mKeyguardFlipper.userSetup(userSetup);
 
             if (userSetup != mUserSetup) {
                 mUserSetup = userSetup;
+                if (mNotificationPanel != null) {
+                    mNotificationPanel.setQsExpansionEnabled(isDeviceProvisioned() && userSetup);
+                }
                 if (!mUserSetup && mStatusBarView != null)
                     animateCollapseQuickSettings();
             }
@@ -612,6 +606,7 @@
         mPixelFormat = PixelFormat.OPAQUE;
 
         mSystemIconArea = (LinearLayout) mStatusBarView.findViewById(R.id.system_icon_area);
+        mSystemIcons = (LinearLayout) mStatusBarView.findViewById(R.id.system_icons);
         mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons);
         mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons);
         mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon);
@@ -630,38 +625,26 @@
                 (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate(
                         R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false);
         mKeyguardIconOverflowContainer.setOnActivatedListener(this);
-        mKeyguardCarrierLabel = mStatusBarWindow.findViewById(R.id.keyguard_carrier_text);
-        // TODO: Comment in when transition is ready.
-        //mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
+        mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
         mStackScroller.addView(mKeyguardIconOverflowContainer);
 
         mExpandedContents = mStackScroller;
 
-        mNotificationPanelHeader = mStatusBarWindow.findViewById(R.id.header);
+        mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header);
         mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
         mKeyguardBottomArea =
                 (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area);
         mKeyguardBottomArea.setActivityStarter(this);
         mKeyguardIndicationTextView = (KeyguardIndicationTextView) mStatusBarWindow.findViewById(
                 R.id.keyguard_indication_text);
-        mClearButton = mStatusBarWindow.findViewById(R.id.clear_all_button);
-        mClearButton.setOnClickListener(mClearButtonListener);
-        mClearButton.setAlpha(0f);
-        mClearButton.setVisibility(View.INVISIBLE);
-        mClearButton.setEnabled(false);
         mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date);
 
-        mHasQuickSettings = res.getBoolean(R.bool.config_hasQuickSettings);
-
-        mDateTimeView = mNotificationPanelHeader.findViewById(R.id.datetime);
+        mDateTimeView = mHeader.findViewById(R.id.datetime);
         if (mDateTimeView != null) {
             mDateTimeView.setOnClickListener(mClockClickListener);
             mDateTimeView.setEnabled(true);
         }
 
-        mHeaderFlipper = new FlipperButton(mStatusBarWindow.findViewById(R.id.header_flipper));
-        mKeyguardFlipper =new FlipperButton(mStatusBarWindow.findViewById(R.id.keyguard_flipper));
-
         if (!mNotificationPanelIsFullScreenWidth) {
             mNotificationPanel.setSystemUiVisibility(
                     View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS |
@@ -735,26 +718,23 @@
 //                    updateCarrierLabelVisibility(false);
         }
 
-        // Quick Settings (where available, some restrictions apply)
-        if (mHasQuickSettings) {
-            // Quick Settings needs a container to survive
-            mSettingsContainer = (QuickSettingsContainerView)
-                    mStatusBarWindow.findViewById(R.id.quick_settings_container);
-            mFlipSettingsView = mSettingsContainer;
-            if (mSettingsContainer != null) {
-                mQS = new QuickSettings(mContext, mSettingsContainer);
-                if (!mNotificationPanelIsFullScreenWidth) {
-                    mSettingsContainer.setSystemUiVisibility(
-                            View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS
-                            | View.STATUS_BAR_DISABLE_SYSTEM_INFO);
-                }
-                mQS.setService(this);
-                mQS.setBar(mStatusBarView);
-                mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
-                        mLocationController, mRotationLockController);
-            } else {
-                mQS = null; // fly away, be free
+        // Quick Settings needs a container to survive
+        mSettingsContainer = (QuickSettingsContainerView)
+                mStatusBarWindow.findViewById(R.id.quick_settings_container);
+        mFlipSettingsView = mSettingsContainer;
+        if (mSettingsContainer != null) {
+            mQS = new QuickSettings(mContext, mSettingsContainer);
+            if (!mNotificationPanelIsFullScreenWidth) {
+                mSettingsContainer.setSystemUiVisibility(
+                        View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS
+                        | View.STATUS_BAR_DISABLE_SYSTEM_INFO);
             }
+            mQS.setService(this);
+            mQS.setBar(mStatusBarView);
+            mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
+                    mLocationController, mRotationLockController);
+        } else {
+            mQS = null; // fly away, be free
         }
 
         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -775,101 +755,6 @@
         return mStatusBarView;
     }
 
-    public boolean onSettingsEvent(MotionEvent event) {
-        userActivity();
-        if (mSettingsClosing
-                && mFlipSettingsViewAnim != null && mFlipSettingsViewAnim.isRunning()) {
-            return true;
-        }
-        if (mSettingsTracker != null) {
-            mSettingsTracker.addMovement(event);
-        }
-        final int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
-        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-            mSettingsTracker = VelocityTracker.obtain();
-            mSettingsDownY = event.getY();
-            mSettingsCancelled = false;
-            mSettingsStarted = false;
-            mSettingsClosing = mFlipSettingsView.getVisibility() == View.VISIBLE;
-            if (mSettingsClosing) {
-                mStackScroller.setVisibility(View.VISIBLE);
-            } else {
-                mFlipSettingsView.setTranslationY(-mNotificationPanel.getMeasuredHeight());
-            }
-            dispatchSettingsEvent(event);
-        } else if (mSettingsTracker != null && (event.getAction() == MotionEvent.ACTION_UP
-                || event.getAction() == MotionEvent.ACTION_CANCEL)) {
-            final float dy = event.getY() - mSettingsDownY;
-            final FlipperButton flipper = mState == StatusBarState.KEYGUARD
-                    ? mKeyguardFlipper
-                    : mHeaderFlipper;
-            final boolean inButton = flipper.inHolderBounds(event);
-            final boolean qsTap = mSettingsClosing && Math.abs(dy) < slop;
-            if (!qsTap && !inButton) {
-                mSettingsTracker.computeCurrentVelocity(1000);
-                final float vy = mSettingsTracker.getYVelocity();
-                final boolean animate = true;
-                if (dy <= slop || vy <= 0) {
-                    flipToNotifications(animate);
-                } else {
-                    flipToSettings(animate);
-                }
-            }
-            mSettingsTracker.recycle();
-            mSettingsTracker = null;
-            dispatchSettingsEvent(event);
-        } else if (mSettingsTracker != null && event.getAction() == MotionEvent.ACTION_MOVE) {
-            final float dy = event.getY() - mSettingsDownY;
-            if (mSettingsClosing) {
-                positionSettings(dy);
-                final boolean qsTap = Math.abs(dy) < slop;
-                if (!mSettingsCancelled && !qsTap) {
-                    MotionEvent cancelEvent = MotionEvent.obtainNoHistory(event);
-                    cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
-                    dispatchSettingsEvent(cancelEvent);
-                    mSettingsCancelled = true;
-                }
-            } else {
-                if (!mSettingsStarted && dy > slop) {
-                    mSettingsStarted = true;
-                    mFlipSettingsView.setVisibility(View.VISIBLE);
-                    mStackScroller.setVisibility(View.VISIBLE);
-                }
-                if (mSettingsStarted) {
-                    positionSettings(dy);
-                }
-                dispatchSettingsEvent(event);
-            }
-        }
-        return true;
-    }
-
-    private void dispatchSettingsEvent(MotionEvent event) {
-        final View target = mSettingsClosing ? mFlipSettingsView : mNotificationPanelHeader;
-        final int[] targetLoc = new int[2];
-        target.getLocationInWindow(targetLoc);
-        final int[] panelLoc = new int[2];
-        mNotificationPanel.getLocationInWindow(panelLoc);
-        final int dx = targetLoc[0] - panelLoc[0];
-        final int dy = targetLoc[1] - panelLoc[1];
-        event.offsetLocation(-dx, -dy);
-        target.dispatchTouchEvent(event);
-    }
-
-    private void positionSettings(float dy) {
-        if (mSettingsClosing) {
-            final int ph = mNotificationPanel.getMeasuredHeight();
-            dy = Math.min(Math.max(-ph, dy), 0);
-            mFlipSettingsView.setTranslationY(dy);
-            mStackScroller.setTranslationY(ph + dy);
-        } else {
-            final int h = mFlipSettingsView.getBottom();
-            dy = Math.min(Math.max(0, dy), h);
-            mFlipSettingsView.setTranslationY(-h + dy);
-            mStackScroller.setTranslationY(dy);
-        }
-    }
-
     private void startKeyguard() {
         KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
         mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
@@ -1223,16 +1108,6 @@
         if (mNavigationBarView != null) {
             mNavigationBarView.setLayoutDirection(layoutDirection);
         }
-
-        if (mClearButton != null && mClearButton instanceof ImageView) {
-            // Force asset reloading
-            ((ImageView)mClearButton).setImageDrawable(null);
-            ((ImageView)mClearButton).setImageResource(R.drawable.ic_notify_clear);
-        }
-
-        mHeaderFlipper.refreshLayout();
-        mKeyguardFlipper.refreshLayout();
-
         refreshAllStatusBarIcons();
     }
 
@@ -1286,8 +1161,7 @@
             }
         }
 
-        mHeaderFlipper.provisionCheck(provisioned);
-        mKeyguardFlipper.provisionCheck(provisioned);
+        mNotificationPanel.setQsExpansionEnabled(provisioned && mUserSetup);
     }
 
     @Override
@@ -1362,7 +1236,7 @@
         final boolean makeVisible =
             !(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
             && mStackScroller.getHeight() < (mNotificationPanel.getHeight()
-                    - mCarrierLabelHeight - mNotificationHeaderHeight)
+                    - mCarrierLabelHeight - mStatusBarHeaderHeight)
             && mStackScroller.getVisibility() == View.VISIBLE
             && mState != StatusBarState.KEYGUARD;
 
@@ -1404,38 +1278,6 @@
                     + " any=" + any + " clearable=" + clearable);
         }
 
-        if (mFlipSettingsView != null
-                && mFlipSettingsView.getVisibility() == View.VISIBLE
-                && mStackScroller.getVisibility() != View.VISIBLE) {
-            // the flip settings panel is unequivocally showing; we should not be shown
-            mClearButton.setVisibility(View.INVISIBLE);
-        } else if (mClearButton.isShown()) {
-            if (clearable != (mClearButton.getAlpha() == 1.0f)) {
-                ObjectAnimator clearAnimation = ObjectAnimator.ofFloat(
-                        mClearButton, "alpha", clearable ? 1.0f : 0.0f).setDuration(250);
-                clearAnimation.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        if (mClearButton.getAlpha() <= 0.0f) {
-                            mClearButton.setVisibility(View.INVISIBLE);
-                        }
-                    }
-
-                    @Override
-                    public void onAnimationStart(Animator animation) {
-                        if (mClearButton.getAlpha() <= 0.0f) {
-                            mClearButton.setVisibility(View.VISIBLE);
-                        }
-                    }
-                });
-                clearAnimation.start();
-            }
-        } else {
-            mClearButton.setAlpha(clearable ? 1.0f : 0.0f);
-            mClearButton.setVisibility(clearable ? View.VISIBLE : View.INVISIBLE);
-        }
-        mClearButton.setEnabled(clearable);
-
         final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out);
         final boolean showDot = (any&&!areLightsOn());
         if (showDot != (nlo.getAlpha() == 1.0f)) {
@@ -1775,47 +1617,8 @@
     }
 
     public void flipToNotifications(boolean animate) {
-        cancelAnim(mFlipSettingsViewAnim);
-        cancelAnim(mScrollViewAnim);
-        cancelAnim(mClearButtonAnim);
-        mHeaderFlipper.cancel();
-        mKeyguardFlipper.cancel();
-        mStackScroller.setVisibility(View.VISIBLE);
-        final int h = mNotificationPanel.getMeasuredHeight();
-        if (animate) {
-            final float settingsY =
-                    mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : 0;
-            final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : h;
-            mScrollViewAnim = start(
-                    interpolator(mDecelerateInterpolator,
-                        ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, 0)
-                            .setDuration(FLIP_DURATION)
-                        ));
-            mFlipSettingsViewAnim = start(
-                setVisibilityWhenDone(
-                    interpolator(mDecelerateInterpolator,
-                            ObjectAnimator.ofFloat(
-                                    mFlipSettingsView, View.TRANSLATION_Y, settingsY, -h))
-                        .setDuration(FLIP_DURATION),
-                    mFlipSettingsView, View.INVISIBLE));
-        } else {
-            mStackScroller.setTranslationY(0);
-            mFlipSettingsView.setTranslationY(-h);
-            mFlipSettingsView.setVisibility(View.INVISIBLE);
-        }
-        mHeaderFlipper.flipToNotifications(animate);
-        mKeyguardFlipper.flipToNotifications(animate);
-        mClearButton.setVisibility(View.VISIBLE);
-        mClearButton.setAlpha(0f);
-        setAreThereNotifications(); // this will show/hide the button as necessary
-        mNotificationPanel.postDelayed(new Runnable() {
-            public void run() {
-                updateCarrierLabelVisibility(false);
-            }
-        }, animate ? FLIP_DURATION - 150 : 0);
-        if (mOnFlipRunnable != null) {
-            mOnFlipRunnable.run();
-        }
+        // TODO: Animation
+        mNotificationPanel.closeQs();
     }
 
     @Override
@@ -1829,78 +1632,18 @@
         if (!mUserSetup) return;
 
         mNotificationPanel.expand();
-        if (mFlipSettingsView.getVisibility() != View.VISIBLE
-                || mFlipSettingsView.getTranslationY() < 0) {
-            flipToSettings(true /*animate*/);
-        }
+        mNotificationPanel.openQs();
 
         if (false) postStartTracing();
     }
 
     public boolean isFlippedToSettings() {
-        if (mFlipSettingsView != null) {
-            return mFlipSettingsView.getVisibility() == View.VISIBLE;
+        if (mNotificationPanel != null) {
+            return mNotificationPanel.isQsExpanded();
         }
         return false;
     }
 
-    public void flipToSettings(boolean animate) {
-        // Settings are not available in setup
-        if (!mUserSetup) return;
-
-        cancelAnim(mFlipSettingsViewAnim);
-        cancelAnim(mScrollViewAnim);
-        mHeaderFlipper.cancel();
-        mKeyguardFlipper.cancel();
-        cancelAnim(mClearButtonAnim);
-
-        mFlipSettingsView.setVisibility(View.VISIBLE);
-        final int h = mNotificationPanel.getMeasuredHeight();
-        if (animate) {
-            final float settingsY
-                    = mSettingsTracker != null ? mFlipSettingsView.getTranslationY() : -h;
-            final float scrollerY = mSettingsTracker != null ? mStackScroller.getTranslationY() : 0;
-            mFlipSettingsViewAnim = start(
-                    startDelay(0,
-                        interpolator(mDecelerateInterpolator,
-                            ObjectAnimator.ofFloat(mFlipSettingsView, View.TRANSLATION_Y,
-                                    settingsY, 0f)
-                                .setDuration(FLIP_DURATION)
-                            )));
-            mScrollViewAnim = start(
-                setVisibilityWhenDone(
-                    interpolator(mDecelerateInterpolator,
-                            ObjectAnimator.ofFloat(mStackScroller, View.TRANSLATION_Y, scrollerY, h)
-                            )
-                        .setDuration(FLIP_DURATION),
-                        mStackScroller, View.INVISIBLE));
-        } else {
-            mFlipSettingsView.setTranslationY(0);
-            mStackScroller.setTranslationY(h);
-            mStackScroller.setVisibility(View.INVISIBLE);
-        }
-        mHeaderFlipper.flipToSettings(animate);
-        mKeyguardFlipper.flipToSettings(animate);
-        if (animate) {
-            mClearButtonAnim = start(
-                setVisibilityWhenDone(
-                    ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f)
-                    .setDuration(FLIP_DURATION),
-                    mClearButton, View.INVISIBLE));
-        } else {
-            mClearButton.setAlpha(0);
-            mClearButton.setVisibility(View.INVISIBLE);
-        }
-        mNotificationPanel.postDelayed(new Runnable() {
-            public void run() {
-                updateCarrierLabelVisibility(false);
-            }
-        }, animate ? FLIP_DURATION - 150 : 0);
-        if (mOnFlipRunnable != null) {
-            mOnFlipRunnable.run();
-        }
-    }
-
     public void animateCollapseQuickSettings() {
         mStatusBarView.collapseAllPanels(true);
     }
@@ -1927,12 +1670,10 @@
 
         mStackScroller.setVisibility(View.VISIBLE);
         mNotificationPanel.setVisibility(View.GONE);
-        mFlipSettingsView.setVisibility(View.GONE);
 
         setAreThereNotifications(); // show the clear button
 
-        mHeaderFlipper.reset();
-        mKeyguardFlipper.reset();
+        mNotificationPanel.closeQs();
 
         mExpandedVisible = false;
         if (mNavigationBarView != null)
@@ -2463,20 +2204,11 @@
         }
     }
 
-    void updateExpandedInvisiblePosition() {
-        mTrackingPosition = -mDisplayMetrics.heightPixels;
-    }
-
     static final float saturate(float a) {
         return a < 0f ? 0f : (a > 1f ? 1f : a);
     }
 
     @Override
-    protected int getExpandedViewMaxHeight() {
-        return mDisplayMetrics.heightPixels - mNotificationPanelMarginBottomPx;
-    }
-
-    @Override
     public void updateExpandedViewPos(int thingy) {
         if (SPEW) Log.v(TAG, "updateExpandedViewPos");
 
@@ -2486,15 +2218,8 @@
 
         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mNotificationPanel.getLayoutParams();
         lp.gravity = mNotificationPanelGravity;
-        lp.setMarginStart(mNotificationPanelMarginPx);
         mNotificationPanel.setLayoutParams(lp);
 
-        if (ENABLE_HEADS_UP && mHeadsUpNotificationView != null) {
-            mHeadsUpNotificationView.setMargin(mNotificationPanelMarginPx);
-            mStackScroller.getLocationOnScreen(mStackScrollerPosition);
-            mHeadsUpVerticalOffset = mStackScrollerPosition[1] - mNaturalBarHeight;
-        }
-
         updateCarrierLabelVisibility(false);
     }
 
@@ -2542,17 +2267,6 @@
         animateCollapsePanels();
     }
 
-    private View.OnClickListener mSettingsButtonListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            if (mHasQuickSettings) {
-                animateExpandSettingsPanel();
-            } else {
-                startActivityDismissingKeyguard(
-                        new Intent(android.provider.Settings.ACTION_SETTINGS), true);
-            }
-        }
-    };
-
     private View.OnClickListener mClockClickListener = new View.OnClickListener() {
         public void onClick(View v) {
             startActivityDismissingKeyguard(
@@ -2653,17 +2367,6 @@
         }
     }
 
-    public void animateHeadsUp(boolean animateInto, float frac) {
-        if (!ENABLE_HEADS_UP || mHeadsUpNotificationView == null) return;
-        frac = frac / 0.4f;
-        frac = frac < 1.0f ? frac : 1.0f;
-        float alpha = 1.0f - frac;
-        float offset = mHeadsUpVerticalOffset * frac;
-        offset = animateInto ? offset : 0f;
-        mHeadsUpNotificationView.setAlpha(alpha);
-        mHeadsUpNotificationView.setY(offset);
-    }
-
     public void onHeadsUpDismissed() {
         if (mInterruptingNotificationEntry == null) return;
         mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP);
@@ -2691,10 +2394,6 @@
         final Context context = mContext;
         final Resources res = context.getResources();
 
-        if (mClearButton instanceof TextView) {
-            ((TextView)mClearButton).setText(context.getText(R.string.status_bar_clear_all_button));
-        }
-
         // Update the QuickSettings container
         if (mQS != null) mQS.updateResources();
 
@@ -2736,17 +2435,13 @@
 
         mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity);
 
-        mNotificationPanelMarginBottomPx
-            = (int) res.getDimension(R.dimen.notification_panel_margin_bottom);
-        mNotificationPanelMarginPx
-            = (int) res.getDimension(R.dimen.notification_panel_margin_left);
         mNotificationPanelGravity = res.getInteger(R.integer.notification_panel_layout_gravity);
         if (mNotificationPanelGravity <= 0) {
             mNotificationPanelGravity = Gravity.START | Gravity.TOP;
         }
 
         mCarrierLabelHeight = res.getDimensionPixelSize(R.dimen.carrier_label_height);
-        mNotificationHeaderHeight = res.getDimensionPixelSize(R.dimen.notification_panel_header_height);
+        mStatusBarHeaderHeight = res.getDimensionPixelSize(R.dimen.status_bar_header_height);
 
         mNotificationPanelMinHeightFrac = res.getFraction(R.dimen.notification_panel_min_height_frac, 1, 1);
         if (mNotificationPanelMinHeightFrac < 0f || mNotificationPanelMinHeightFrac > 1f) {
@@ -3016,29 +2711,21 @@
 
     private void updateKeyguardState() {
         if (mState == StatusBarState.KEYGUARD) {
-            if (isFlippedToSettings()) {
-                flipToNotifications(false /*animate*/);
-            }
             mKeyguardStatusView.setVisibility(View.VISIBLE);
             mKeyguardBottomArea.setVisibility(View.VISIBLE);
             mKeyguardIndicationTextView.setVisibility(View.VISIBLE);
             mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
-            mKeyguardCarrierLabel.setVisibility(View.VISIBLE);
-            mNotificationPanelHeader.setVisibility(View.GONE);
 
-            mKeyguardFlipper.setVisibility(View.VISIBLE);
-            mSettingsContainer.setKeyguardShowing(true);
+            mNotificationPanel.closeQs();
         } else {
             mKeyguardStatusView.setVisibility(View.GONE);
             mKeyguardBottomArea.setVisibility(View.GONE);
             mKeyguardIndicationTextView.setVisibility(View.GONE);
-            mKeyguardCarrierLabel.setVisibility(View.GONE);
-            mNotificationPanelHeader.setVisibility(View.VISIBLE);
-
-            mKeyguardFlipper.setVisibility(View.GONE);
-            mSettingsContainer.setKeyguardShowing(false);
         }
+        mSettingsContainer.setKeyguardShowing(mState == StatusBarState.KEYGUARD);
+        mHeader.setKeyguardShowing(mState == StatusBarState.KEYGUARD);
 
+        updateStackScrollerState();
         updatePublicMode();
         updateRowStates();
         checkBarModes();
@@ -3046,6 +2733,10 @@
         updateCarrierLabelVisibility(false);
     }
 
+    public void updateStackScrollerState() {
+        mStackScroller.setDimmed(mState == StatusBarState.KEYGUARD, false /* animate */);
+    }
+
     public void userActivity() {
         if (mState == StatusBarState.KEYGUARD) {
             mKeyguardViewMediatorCallback.userActivity();
@@ -3099,7 +2790,7 @@
     public void onActivated(View view) {
         userActivity();
         mKeyguardIndicationTextView.switchIndication(R.string.notification_tap_again);
-        super.onActivated(view);
+        mStackScroller.setActivatedChild(view);
     }
 
     /**
@@ -3111,9 +2802,11 @@
     }
 
     @Override
-    public void onReset(View view) {
-        super.onReset(view);
-        mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+    public void onActivationReset(View view) {
+        if (view == mStackScroller.getActivatedChild()) {
+            mKeyguardIndicationTextView.switchIndication(mKeyguardHotwordPhrase);
+            mStackScroller.setActivatedChild(null);
+        }
     }
 
     public void onTrackingStarted() {
@@ -3145,30 +2838,12 @@
     }
 
     @Override
-    public void onReset() {
-        int n = mNotificationData.size();
-        for (int i = 0; i < n; i++) {
-            NotificationData.Entry entry = mNotificationData.get(i);
-            if (entry.row.getVisibility() != View.GONE) {
-                entry.row.setDimmed(true /* dimmed */, true /* fade */);
-            }
-        }
-        if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
-            mKeyguardIconOverflowContainer.setDimmed(true /* dimmed */, true /* fade */);
-        }
+    public void onDragDownReset() {
+        mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
     }
 
     public void onThresholdReached() {
-        int n = mNotificationData.size();
-        for (int i = 0; i < n; i++) {
-            NotificationData.Entry entry = mNotificationData.get(i);
-            if (entry.row.getVisibility() != View.GONE) {
-                entry.row.setDimmed(false /* dimmed */, true /* fade */);
-            }
-        }
-        if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
-            mKeyguardIconOverflowContainer.setDimmed(false /* dimmed */, true /* fade */);
-        }
+        mStackScroller.setDimmed(false /* dimmed */, true /* animate */);
     }
 
     /**
@@ -3202,131 +2877,17 @@
      * @return a ViewGroup that spans the entire panel which contains the quick settings
      */
     public ViewGroup getQuickSettingsOverlayParent() {
-        if (mHasQuickSettings) {
-            return mNotificationPanel;
-        } else {
-            return null;
-        }
+        return mNotificationPanel;
     }
 
-    public static boolean inBounds(View view, MotionEvent event, boolean orAbove) {
-        final int[] location = new int[2];
-        view.getLocationInWindow(location);
-        final int rx = (int) event.getRawX();
-        final int ry = (int) event.getRawY();
-        return rx >= location[0] && rx <= location[0] + view.getMeasuredWidth()
-                && (orAbove || ry >= location[1]) && ry <= location[1] + view.getMeasuredHeight();
+    public LinearLayout getSystemIcons() {
+        return mSystemIcons;
     }
 
-    private final class FlipperButton {
-        private final View mHolder;
-
-        private ImageView mSettingsButton, mNotificationButton;
-        private Animator mSettingsButtonAnim, mNotificationButtonAnim;
-
-        public FlipperButton(View holder) {
-            mHolder = holder;
-            mSettingsButton = (ImageView) holder.findViewById(R.id.settings_button);
-            if (mSettingsButton != null) {
-                mSettingsButton.setOnClickListener(mSettingsButtonListener);
-                if (mHasQuickSettings) {
-                    // the settings panel is hiding behind this button
-                    mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
-                    mSettingsButton.setVisibility(View.VISIBLE);
-                } else {
-                    // no settings panel, go straight to settings
-                    mSettingsButton.setVisibility(View.VISIBLE);
-                    mSettingsButton.setImageResource(R.drawable.ic_notify_settings);
-                }
-            }
-            mNotificationButton = (ImageView) holder.findViewById(R.id.notification_button);
-            if (mNotificationButton != null) {
-                mNotificationButton.setOnClickListener(mNotificationButtonListener);
-            }
-        }
-
-        public boolean inHolderBounds(MotionEvent event) {
-            return inBounds(mHolder, event, false);
-        }
-
-        public void provisionCheck(boolean provisioned) {
-            if (mSettingsButton != null) {
-                mSettingsButton.setEnabled(provisioned);
-            }
-        }
-
-        public void userSetup(boolean userSetup) {
-            if (mSettingsButton != null) {
-                mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE);
-            }
-        }
-
-        public void reset() {
-            cancel();
-            mSettingsButton.setVisibility(View.VISIBLE);
-            mNotificationButton.setVisibility(View.GONE);
-        }
-
-        public void refreshLayout() {
-            if (mSettingsButton != null) {
-                // Force asset reloading
-                mSettingsButton.setImageDrawable(null);
-                mSettingsButton.setImageResource(R.drawable.ic_notify_quicksettings);
-            }
-
-            if (mNotificationButton != null) {
-                // Force asset reloading
-                mNotificationButton.setImageDrawable(null);
-                mNotificationButton.setImageResource(R.drawable.ic_notifications);
-            }
-        }
-
-        public void flipToSettings(boolean animate) {
-            mNotificationButton.setVisibility(View.VISIBLE);
-            if (animate) {
-                mSettingsButtonAnim = start(
-                    setVisibilityWhenDone(
-                        ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
-                            .setDuration(FLIP_DURATION_OUT),
-                        mStackScroller, View.INVISIBLE));
-                mNotificationButtonAnim = start(
-                    startDelay(FLIP_DURATION_OUT,
-                        ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
-                            .setDuration(FLIP_DURATION_IN)));
-            } else {
-                mSettingsButton.setAlpha(0f);
-                mSettingsButton.setVisibility(View.INVISIBLE);
-                mNotificationButton.setAlpha(1f);
-            }
-        }
-
-        public void flipToNotifications(boolean animate) {
-            mSettingsButton.setVisibility(View.VISIBLE);
-            if (animate) {
-                mNotificationButtonAnim = start(
-                    setVisibilityWhenDone(
-                        ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f)
-                            .setDuration(FLIP_DURATION_OUT),
-                        mNotificationButton, View.INVISIBLE));
-
-                mSettingsButtonAnim = start(
-                    startDelay(FLIP_DURATION_OUT,
-                        ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f)
-                            .setDuration(FLIP_DURATION_IN)));
-            } else {
-                mNotificationButton.setVisibility(View.INVISIBLE);
-                mNotificationButton.setAlpha(0f);
-                mSettingsButton.setAlpha(1f);
-            }
-        }
-
-        public void cancel() {
-            cancelAnim(mSettingsButtonAnim);
-            cancelAnim(mNotificationButtonAnim);
-        }
-
-        public void setVisibility(int vis) {
-            mHolder.setVisibility(vis);
-        }
+    /**
+     * Reattaches the system icons to its normal parent in collapsed status bar.
+     */
+    public void reattachSystemIcons() {
+        mSystemIconArea.addView(mSystemIcons, 0);
     }
 }
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..e941d54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarTransitions.java
@@ -44,12 +44,16 @@
 
     public void init() {
         mLeftSide = mView.findViewById(R.id.notification_icon_area);
+        initStatus();
+        applyModeBackground(-1, getMode(), false /*animate*/);
+        applyMode(getMode(), false /*animate*/);
+    }
+
+    private void initStatus() {
         mStatusIcons = mView.findViewById(R.id.statusIcons);
         mSignalCluster = mView.findViewById(R.id.signal_cluster);
         mBattery = mView.findViewById(R.id.battery);
         mClock = mView.findViewById(R.id.clock);
-        applyModeBackground(-1, getMode(), false /*animate*/);
-        applyMode(getMode(), false /*animate*/);
     }
 
     public ObjectAnimator animateTransitionTo(View v, float toAlpha) {
@@ -79,6 +83,8 @@
 
     private void applyMode(int mode, boolean animate) {
         if (mLeftSide == null) return; // pre-init
+        if (mStatusIcons == null) initStatus();
+        if (mStatusIcons == null) return;
         float newAlpha = getNonBatteryClockAlphaFor(mode);
         float newAlphaBC = getBatteryClockAlpha(mode);
         if (mCurrentAnimation != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 10c1625..e6de057 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -220,8 +220,6 @@
             panel.setAlpha(alpha);
         }
 
-        mBar.animateHeadsUp(mNotificationPanel == panel, mPanelExpandedFractionSum);
-
         mBar.updateCarrierLabelVisibility(false);
         mBar.userActivity();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
new file mode 100644
index 0000000..67487ab
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.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.phone;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+
+import com.android.systemui.R;
+
+/**
+ * The view to manage the header area in the expanded status bar.
+ */
+public class StatusBarHeaderView extends RelativeLayout {
+
+    private boolean mExpanded;
+    private View mBackground;
+    private ViewGroup mSystemIconsContainer;
+    private View mDateTime;
+    private View mKeyguardCarrierText;
+
+    private int mCollapsedHeight;
+    private int mExpandedHeight;
+    private int mKeyguardHeight;
+
+    private boolean mKeyguardShowing;
+
+    public StatusBarHeaderView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mBackground = findViewById(R.id.background);
+        mSystemIconsContainer = (ViewGroup) findViewById(R.id.system_icons_container);
+        mDateTime = findViewById(R.id.datetime);
+        mKeyguardCarrierText = findViewById(R.id.keyguard_carrier_text);
+        loadDimens();
+    }
+
+    private void loadDimens() {
+        mCollapsedHeight = getResources().getDimensionPixelSize(R.dimen.status_bar_header_height);
+        mExpandedHeight = getResources().getDimensionPixelSize(
+                R.dimen.status_bar_header_height_expanded);
+        mKeyguardHeight = getResources().getDimensionPixelSize(
+                R.dimen.status_bar_header_height_keyguard);
+    }
+
+    public int getCollapsedHeight() {
+        return mKeyguardShowing ? mKeyguardHeight : mCollapsedHeight;
+    }
+
+    public int getExpandedHeight() {
+        return mExpandedHeight;
+    }
+
+    public void setExpanded(boolean expanded) {
+        mExpanded = expanded;
+        updateHeights();
+    }
+
+    private void updateHeights() {
+        int height;
+        if (mExpanded) {
+            height = mExpandedHeight;
+        } else if (mKeyguardShowing) {
+            height = mKeyguardHeight;
+        } else {
+            height = mCollapsedHeight;
+        }
+        ViewGroup.LayoutParams lp = getLayoutParams();
+        if (lp.height != height) {
+            lp.height = height;
+            setLayoutParams(lp);
+        }
+        int systemIconsContainerHeight = mKeyguardShowing ? mKeyguardHeight : mCollapsedHeight;
+        lp = mSystemIconsContainer.getLayoutParams();
+        if (lp.height != systemIconsContainerHeight) {
+            lp.height = systemIconsContainerHeight;
+            mSystemIconsContainer.setLayoutParams(lp);
+        }
+    }
+
+    public void setExpansion(float height) {
+        if (height < mCollapsedHeight) {
+            height = mCollapsedHeight;
+        }
+        if (height > mExpandedHeight) {
+            height = mExpandedHeight;
+        }
+        if (mExpanded) {
+            mBackground.setTranslationY(-(mExpandedHeight - height));
+        } else {
+            mBackground.setTranslationY(0);
+        }
+    }
+
+    public View getBackgroundView() {
+        return mBackground;
+    }
+
+    public void attachSystemIcons(LinearLayout systemIcons) {
+        mSystemIconsContainer.addView(systemIcons);
+    }
+
+    public void setKeyguardShowing(boolean keyguardShowing) {
+        mKeyguardShowing = keyguardShowing;
+        mBackground.setVisibility(keyguardShowing ? View.INVISIBLE : View.VISIBLE);
+        mDateTime.setVisibility(keyguardShowing ? View.INVISIBLE : View.VISIBLE);
+        mKeyguardCarrierText.setVisibility(keyguardShowing ? View.VISIBLE : View.GONE);
+        if (keyguardShowing) {
+            setZ(0);
+        } else {
+            setTranslationZ(0);
+        }
+        updateHeights();
+    }
+}
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 e24ddd9..48c54fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -73,8 +73,7 @@
     public void show(Bundle options) {
         mShowing = true;
         mStatusBarWindowManager.setKeyguardShowing(true);
-        showBouncerOrKeyguard();
-        updateStates();
+        reset();
     }
 
     /**
@@ -95,7 +94,9 @@
     }
 
     private void showBouncer() {
-        mBouncer.show();
+        if (!mOccluded) {
+            mBouncer.show();
+        }
         updateStates();
     }
 
@@ -103,8 +104,15 @@
      * Reset the state of the view.
      */
     public void reset() {
-        showBouncerOrKeyguard();
-        updateStates();
+        if (mShowing) {
+            if (mOccluded) {
+                mPhoneStatusBar.hideKeyguard();
+                mBouncer.hide();
+            } else {
+                showBouncerOrKeyguard();
+            }
+            updateStates();
+        }
     }
 
     public void onScreenTurnedOff() {
@@ -147,7 +155,7 @@
     public void setOccluded(boolean occluded) {
         mOccluded = occluded;
         mStatusBarWindowManager.setKeyguardOccluded(occluded);
-        updateStates();
+        reset();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 4c9264d..e802d185 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -56,11 +56,14 @@
     @Override
     protected boolean fitSystemWindows(Rect insets) {
         if (getFitsSystemWindows()) {
-            setPadding(insets.left, insets.top, insets.right, insets.bottom);
+            setPadding(insets.left, insets.top, insets.right, 0);
+            insets.left = 0;
+            insets.top = 0;
+            insets.right = 0;
         } else {
             setPadding(0, 0, 0, 0);
         }
-        return true;
+        return false;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
new file mode 100644
index 0000000..4121a40
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -0,0 +1,75 @@
+/*
+ * 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.stack;
+
+import android.view.View;
+
+import java.util.ArrayList;
+
+/**
+ * A global state to track all input states for the algorithm.
+ */
+public class AmbientState {
+    private ArrayList<View> mDraggedViews = new ArrayList<View>();
+    private int mScrollY;
+    private boolean mDimmed;
+    private View mActivatedChild;
+
+    public int getScrollY() {
+        return mScrollY;
+    }
+
+    public void setScrollY(int scrollY) {
+        this.mScrollY = scrollY;
+    }
+
+    public void onBeginDrag(View view) {
+        mDraggedViews.add(view);
+    }
+
+    public void onDragFinished(View view) {
+        mDraggedViews.remove(view);
+    }
+
+    public ArrayList<View> getDraggedViews() {
+        return mDraggedViews;
+    }
+
+    /**
+     * @param dimmed Whether we are in a dimmed state (on the lockscreen), where the backgrounds are
+     *               translucent and everything is scaled back a bit.
+     */
+    public void setDimmed(boolean dimmed) {
+        mDimmed = dimmed;
+    }
+
+    /**
+     * In dimmed mode, a child can be activated, which happens on the first tap of the double-tap
+     * interaction. This child is then scaled normally and its background is fully opaque.
+     */
+    public void setActivatedChild(View activatedChild) {
+        mActivatedChild = activatedChild;
+    }
+
+    public boolean isDimmed() {
+        return mDimmed;
+    }
+
+    public View getActivatedChild() {
+        return mActivatedChild;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
new file mode 100644
index 0000000..41914ed
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -0,0 +1,92 @@
+/*
+ * 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.stack;
+
+import java.util.ArrayList;
+
+/**
+ * Filters the animations for only a certain type of properties.
+ */
+public class AnimationFilter {
+    boolean animateAlpha;
+    boolean animateY;
+    boolean animateZ;
+    boolean animateScale;
+    boolean animateHeight;
+    boolean animateDimmed;
+
+    public AnimationFilter animateAlpha() {
+        animateAlpha = true;
+        return this;
+    }
+
+    public AnimationFilter animateY() {
+        animateY = true;
+        return this;
+    }
+
+    public AnimationFilter animateZ() {
+        animateZ = true;
+        return this;
+    }
+
+    public AnimationFilter animateScale() {
+        animateScale = true;
+        return this;
+    }
+
+    public AnimationFilter animateHeight() {
+        animateHeight = true;
+        return this;
+    }
+
+    public AnimationFilter animateDimmed() {
+        animateDimmed = true;
+        return this;
+    }
+
+    /**
+     * Combines multiple filters into {@code this} filter, using or as the operand .
+     *
+     * @param events The animation events from the filters to combine.
+     */
+    public void applyCombination(ArrayList<NotificationStackScrollLayout.AnimationEvent> events) {
+        reset();
+        int size = events.size();
+        for (int i = 0; i < size; i++) {
+            combineFilter(events.get(i).filter);
+        }
+    }
+
+    private void combineFilter(AnimationFilter filter) {
+        animateAlpha |= filter.animateAlpha;
+        animateY |= filter.animateY;
+        animateZ |= filter.animateZ;
+        animateScale |= filter.animateScale;
+        animateHeight |= filter.animateHeight;
+        animateDimmed |= filter.animateDimmed;
+    }
+
+    private void reset() {
+        animateAlpha = false;
+        animateY = false;
+        animateZ = false;
+        animateScale = false;
+        animateHeight = false;
+        animateDimmed = false;
+    }
+}
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 f8aab80..afd5068 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -84,7 +84,6 @@
     private int mEmptyMarginBottom;
     private int mPaddingBetweenElements;
     private int mTopPadding;
-    private boolean mListenForHeightChanges = true;
 
     /**
      * The algorithm which calculates the properties for our children
@@ -95,6 +94,7 @@
      * The current State this Layout is in
      */
     private StackScrollState mCurrentStackScrollState = new StackScrollState(this);
+    private AmbientState mAmbientState = new AmbientState();
     private ArrayList<View> mChildrenToAddAnimated = new ArrayList<View>();
     private ArrayList<View> mChildrenToRemoveAnimated = new ArrayList<View>();
     private ArrayList<View> mSnappedBackChildren = new ArrayList<View>();
@@ -108,6 +108,8 @@
     private ExpandableView.OnHeightChangedListener mOnHeightChangedListener;
     private boolean mNeedsAnimation;
     private boolean mTopPaddingNeedsAnimation;
+    private boolean mDimmedNeedsAnimation;
+    private boolean mActivateNeedsAnimation;
     private boolean mIsExpanded = true;
     private boolean mChildrenUpdateRequested;
     private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
@@ -267,8 +269,8 @@
      * modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
      */
     private void updateChildren() {
-        mCurrentStackScrollState.setScrollY(mOwnScrollY);
-        mStackScrollAlgorithm.getStackScrollState(mCurrentStackScrollState);
+        mAmbientState.setScrollY(mOwnScrollY);
+        mStackScrollAlgorithm.getStackScrollState(mAmbientState, mCurrentStackScrollState);
         if (!isCurrentlyAnimating() && !mNeedsAnimation) {
             applyCurrentState();
         } else {
@@ -385,12 +387,12 @@
             mDragAnimPendingChildren.remove(v);
         }
         mSwipedOutViews.add(v);
-        mStackScrollAlgorithm.onDragFinished(v);
+        mAmbientState.onDragFinished(v);
     }
 
     @Override
     public void onChildSnappedBack(View animView) {
-        mStackScrollAlgorithm.onDragFinished(animView);
+        mAmbientState.onDragFinished(animView);
         if (!mDragAnimPendingChildren.contains(animView)) {
             mSnappedBackChildren.add(animView);
             requestChildrenUpdate();
@@ -404,7 +406,7 @@
     public void onBeginDrag(View v) {
         setSwipingInProgress(true);
         mDragAnimPendingChildren.add(v);
-        mStackScrollAlgorithm.onBeginDrag(v);
+        mAmbientState.onBeginDrag(v);
         requestChildrenUpdate();
         mNeedsAnimation = true;
     }
@@ -492,6 +494,9 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
+        if (!isEnabled()) {
+            return false;
+        }
         boolean scrollerWantsIt = false;
         if (!mSwipingInProgress) {
             scrollerWantsIt = onScrollTouch(ev);
@@ -511,7 +516,7 @@
 
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
-                if (getChildCount() == 0) {
+                if (getChildCount() == 0 || !isInContentBounds(ev)) {
                     return false;
                 }
                 boolean isBeingDragged = !mScroller.isFinished();
@@ -962,6 +967,8 @@
         generateSnapBackEvents();
         generateDragEvents();
         generateTopPaddingEvent();
+        generateActivateEvent();
+        generateDimmedEvent();
         mNeedsAnimation = false;
     }
 
@@ -1009,6 +1016,22 @@
         mTopPaddingNeedsAnimation = false;
     }
 
+    private void generateActivateEvent() {
+        if (mActivateNeedsAnimation) {
+            mAnimationEvents.add(
+                    new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_ACTIVATED_CHILD));
+        }
+        mActivateNeedsAnimation = false;
+    }
+
+    private void generateDimmedEvent() {
+        if (mDimmedNeedsAnimation) {
+            mAnimationEvents.add(
+                    new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_DIMMED));
+        }
+        mDimmedNeedsAnimation = false;
+    }
+
     private boolean onInterceptTouchEventScroll(MotionEvent ev) {
         /*
          * This method JUST determines whether we want to intercept the motion.
@@ -1117,6 +1140,13 @@
         return mIsBeingDragged;
     }
 
+    /**
+     * @return Whether the specified motion event is actually happening over the content.
+     */
+    private boolean isInContentBounds(MotionEvent event) {
+        return event.getY() < getHeight() - getEmptyBottomMargin();
+    }
+
     private void setIsBeingDragged(boolean isDragged) {
         mIsBeingDragged = isDragged;
         if (isDragged) {
@@ -1174,14 +1204,12 @@
 
     @Override
     public void onHeightChanged(ExpandableView view) {
-        if (mListenForHeightChanges && !isCurrentlyAnimating()) {
-            updateContentHeight();
-            updateScrollPositionIfNecessary();
-            if (mOnHeightChangedListener != null) {
-                mOnHeightChangedListener.onHeightChanged(view);
-            }
-            requestChildrenUpdate();
+        updateContentHeight();
+        updateScrollPositionIfNecessary();
+        if (mOnHeightChangedListener != null) {
+            mOnHeightChangedListener.onHeightChanged(view);
         }
+        requestChildrenUpdate();
     }
 
     public void setOnHeightChangedListener(
@@ -1194,10 +1222,34 @@
         mAnimationEvents.clear();
     }
 
+    /**
+     * See {@link AmbientState#setDimmed}.
+     */
+    public void setDimmed(boolean dimmed, boolean animate) {
+        mAmbientState.setDimmed(dimmed);
+        if (animate) {
+            mDimmedNeedsAnimation = true;
+            mNeedsAnimation =  true;
+        }
+        requestChildrenUpdate();
+    }
+
+    /**
+     * See {@link AmbientState#setActivatedChild}.
+     */
+    public void setActivatedChild(View activatedChild) {
+        mAmbientState.setActivatedChild(activatedChild);
+        mActivateNeedsAnimation = true;
+        mNeedsAnimation =  true;
+        requestChildrenUpdate();
+    }
+
+    public View getActivatedChild() {
+        return mAmbientState.getActivatedChild();
+    }
+
     private void applyCurrentState() {
-        mListenForHeightChanges = false;
         mCurrentStackScrollState.apply();
-        mListenForHeightChanges = true;
         if (mListener != null) {
             mListener.onChildLocationsChanged(this);
         }
@@ -1212,21 +1264,120 @@
 
     static class AnimationEvent {
 
-        static int ANIMATION_TYPE_ADD = 1;
-        static int ANIMATION_TYPE_REMOVE = 2;
-        static int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 3;
-        static int ANIMATION_TYPE_TOP_PADDING_CHANGED = 4;
-        static int ANIMATION_TYPE_START_DRAG = 5;
-        static int ANIMATION_TYPE_SNAP_BACK = 6;
+        static AnimationFilter[] FILTERS = new AnimationFilter[] {
+
+                // ANIMATION_TYPE_ADD
+                new AnimationFilter()
+                        .animateAlpha()
+                        .animateHeight()
+                        .animateY()
+                        .animateZ(),
+
+                // ANIMATION_TYPE_REMOVE
+                new AnimationFilter()
+                        .animateAlpha()
+                        .animateHeight()
+                        .animateY()
+                        .animateZ(),
+
+                // ANIMATION_TYPE_REMOVE_SWIPED_OUT
+                new AnimationFilter()
+                        .animateAlpha()
+                        .animateHeight()
+                        .animateY()
+                        .animateZ(),
+
+                // ANIMATION_TYPE_TOP_PADDING_CHANGED
+                new AnimationFilter()
+                        .animateAlpha()
+                        .animateHeight()
+                        .animateY()
+                        .animateDimmed()
+                        .animateScale()
+                        .animateZ(),
+
+                // ANIMATION_TYPE_START_DRAG
+                new AnimationFilter()
+                        .animateAlpha(),
+
+                // ANIMATION_TYPE_SNAP_BACK
+                new AnimationFilter()
+                        .animateAlpha(),
+
+                // ANIMATION_TYPE_ACTIVATED_CHILD
+                new AnimationFilter()
+                        .animateScale()
+                        .animateAlpha(),
+
+                // ANIMATION_TYPE_DIMMED
+                new AnimationFilter()
+                        .animateScale()
+                        .animateDimmed()
+        };
+
+        static int[] LENGTHS = new int[] {
+
+                // ANIMATION_TYPE_ADD
+                StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+                // ANIMATION_TYPE_REMOVE
+                StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+                // ANIMATION_TYPE_REMOVE_SWIPED_OUT
+                StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+                // ANIMATION_TYPE_TOP_PADDING_CHANGED
+                StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+                // ANIMATION_TYPE_START_DRAG
+                StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+                // ANIMATION_TYPE_SNAP_BACK
+                StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
+                // ANIMATION_TYPE_ACTIVATED_CHILD
+                StackStateAnimator.ANIMATION_DURATION_DIMMED_ACTIVATED,
+
+                // ANIMATION_TYPE_DIMMED
+                StackStateAnimator.ANIMATION_DURATION_DIMMED_ACTIVATED,
+        };
+
+        static int ANIMATION_TYPE_ADD = 0;
+        static int ANIMATION_TYPE_REMOVE = 1;
+        static int ANIMATION_TYPE_REMOVE_SWIPED_OUT = 2;
+        static int ANIMATION_TYPE_TOP_PADDING_CHANGED = 3;
+        static int ANIMATION_TYPE_START_DRAG = 4;
+        static int ANIMATION_TYPE_SNAP_BACK = 5;
+        static int ANIMATION_TYPE_ACTIVATED_CHILD = 6;
+        static int ANIMATION_TYPE_DIMMED = 7;
 
         final long eventStartTime;
         final View changingView;
         final int animationType;
+        final AnimationFilter filter;
+        final long length;
 
         AnimationEvent(View view, int type) {
             eventStartTime = AnimationUtils.currentAnimationTimeMillis();
             changingView = view;
             animationType = type;
+            filter = FILTERS[type];
+            length = LENGTHS[type];
+        }
+
+        /**
+         * Combines the length of several animation events into a single value.
+         *
+         * @param events The events of the lengths to combine.
+         * @return The combined length. This is just the maximum of all length.
+         */
+        static long combineLength(ArrayList<AnimationEvent> events) {
+            long length = 0;
+            int size = events.size();
+            for (int i = 0; i < size; i++) {
+                length = Math.max(length, events.get(i).length);
+            }
+            return length;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index f7818c0..5e4d496 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -39,6 +39,10 @@
     private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
     private static final int MAX_ITEMS_IN_TOP_STACK = 3;
 
+    /** When a child is activated, the other cards' alpha fade to this value. */
+    private static final float ACTIVATED_INVERSE_ALPHA = 0.9f;
+    private static final float DIMMED_SCALE = 0.95f;
+
     private int mPaddingBetweenElements;
     private int mCollapsedSize;
     private int mTopStackPeekSize;
@@ -61,7 +65,6 @@
     private ExpandableView mFirstChildWhileExpanding;
     private boolean mExpandedOnStart;
     private int mTopStackTotalSize;
-    private ArrayList<View> mDraggedViews = new ArrayList<View>();
 
     public StackScrollAlgorithm(Context context) {
         initConstants(context);
@@ -93,7 +96,7 @@
     }
 
 
-    public void getStackScrollState(StackScrollState resultState) {
+    public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) {
         // The state of the local variables are saved in an algorithmState to easily subdivide it
         // into multiple phases.
         StackScrollAlgorithmState algorithmState = mTempAlgorithmState;
@@ -107,7 +110,7 @@
         algorithmState.scrolledPixelsTop = 0;
         algorithmState.itemsInBottomStack = 0.0f;
         algorithmState.partialInBottom = 0.0f;
-        algorithmState.scrollY = resultState.getScrollY() + mCollapsedSize;
+        algorithmState.scrollY = ambientState.getScrollY() + mCollapsedSize;
 
         updateVisibleChildren(resultState, algorithmState);
 
@@ -120,19 +123,42 @@
         // Phase 3:
         updateZValuesForState(resultState, algorithmState);
 
-        handleDraggedViews(resultState, algorithmState);
+        handleDraggedViews(ambientState, resultState, algorithmState);
+        updateDimmedActivated(ambientState, resultState, algorithmState);
+    }
+
+    /**
+     * Updates the dimmed and activated states of the children.
+     */
+    private void updateDimmedActivated(AmbientState ambientState, StackScrollState resultState,
+            StackScrollAlgorithmState algorithmState) {
+        boolean dimmed = ambientState.isDimmed();
+        View activatedChild = ambientState.getActivatedChild();
+        int childCount = algorithmState.visibleChildren.size();
+        for (int i = 0; i < childCount; i++) {
+            View child = algorithmState.visibleChildren.get(i);
+            StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
+            childViewState.dimmed = dimmed;
+            childViewState.scale = !dimmed || activatedChild == child
+                    ? 1.0f
+                    : DIMMED_SCALE;
+            if (dimmed && activatedChild != null && child != activatedChild) {
+                childViewState.alpha *= ACTIVATED_INVERSE_ALPHA;
+            }
+        }
     }
 
     /**
      * Handle the special state when views are being dragged
      */
-    private void handleDraggedViews(StackScrollState resultState,
+    private void handleDraggedViews(AmbientState ambientState, StackScrollState resultState,
             StackScrollAlgorithmState algorithmState) {
-        for (View draggedView : mDraggedViews) {
+        ArrayList<View> draggedViews = ambientState.getDraggedViews();
+        for (View draggedView : draggedViews) {
             int childIndex = algorithmState.visibleChildren.indexOf(draggedView);
             if (childIndex >= 0 && childIndex < algorithmState.visibleChildren.size() - 1) {
                 View nextChild = algorithmState.visibleChildren.get(childIndex + 1);
-                if (!mDraggedViews.contains(nextChild)) {
+                if (!draggedViews.contains(nextChild)) {
                     // only if the view is not dragged itself we modify its state to be fully
                     // visible
                     StackScrollState.ViewState viewState = resultState.getViewStateForView(
@@ -595,14 +621,6 @@
         }
     }
 
-    public void onBeginDrag(View view) {
-        mDraggedViews.add(view);
-    }
-
-    public void onDragFinished(View view) {
-        mDraggedViews.remove(view);
-    }
-
     class StackScrollAlgorithmState {
 
         /**
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 70126f5..8fc26d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -37,19 +37,10 @@
 
     private final ViewGroup mHostView;
     private Map<ExpandableView, ViewState> mStateMap;
-    private int mScrollY;
     private final Rect mClipRect = new Rect();
     private int mBackgroundRoundedRectCornerRadius;
     private final Outline mChildOutline = new Outline();
 
-    public int getScrollY() {
-        return mScrollY;
-    }
-
-    public void setScrollY(int scrollY) {
-        this.mScrollY = scrollY;
-    }
-
     public StackScrollState(ViewGroup hostView) {
         mHostView = hostView;
         mStateMap = new HashMap<ExpandableView, ViewState>();
@@ -106,10 +97,12 @@
                 float alpha = child.getAlpha();
                 float yTranslation = child.getTranslationY();
                 float zTranslation = child.getTranslationZ();
+                float scale = child.getScaleX();
                 int height = child.getActualHeight();
                 float newAlpha = state.alpha;
                 float newYTranslation = state.yTranslation;
                 float newZTranslation = state.zTranslation;
+                float newScale = state.scale;
                 int newHeight = state.height;
                 boolean becomesInvisible = newAlpha == 0.0f;
                 if (alpha != newAlpha) {
@@ -147,11 +140,20 @@
                     child.setTranslationZ(newZTranslation);
                 }
 
+                // apply scale
+                if (scale != newScale) {
+                    child.setScaleX(newScale);
+                    child.setScaleY(newScale);
+                }
+
                 // apply height
                 if (height != newHeight) {
-                    child.setActualHeight(newHeight);
+                    child.setActualHeight(newHeight, false /* notifyListeners */);
                 }
 
+                // apply dimming
+                child.setDimmed(state.dimmed, false /* animate */);
+
                 // apply clipping and shadow
                 float newNotificationEnd = newYTranslation + newHeight;
 
@@ -228,6 +230,8 @@
         float zTranslation;
         int height;
         boolean gone;
+        float scale;
+        boolean dimmed;
 
         /**
          * The location this view is currently rendered at.
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 2e700aa..ca383aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -18,7 +18,9 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
 import android.view.View;
 import android.view.animation.AnimationUtils;
@@ -37,17 +39,27 @@
  */
 public class StackStateAnimator {
 
-    private static final int ANIMATION_DURATION = 360;
+    public static final int ANIMATION_DURATION_STANDARD = 360;
+    public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220;
+
     private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
     private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
+    private static final int TAG_ANIMATOR_SCALE = R.id.scale_animator_tag;
     private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
     private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag;
     private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag;
     private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
     private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
+    private static final int TAG_END_SCALE = R.id.scale_animator_end_value_tag;
     private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
     private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag;
     private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag;
+    private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag;
+    private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
+    private static final int TAG_START_SCALE = R.id.scale_animator_start_value_tag;
+    private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
+    private static final int TAG_START_HEIGHT = R.id.height_animator_start_value_tag;
+    private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag;
 
     private final Interpolator mFastOutSlowInInterpolator;
     public NotificationStackScrollLayout mHostLayout;
@@ -58,6 +70,8 @@
     private Set<Animator> mAnimatorSet = new HashSet<Animator>();
     private Stack<AnimatorListenerAdapter> mAnimationListenerPool
             = new Stack<AnimatorListenerAdapter>();
+    private AnimationFilter mAnimationFilter = new AnimationFilter();
+    private long mCurrentLength;
 
     public StackStateAnimator(NotificationStackScrollLayout hostLayout) {
         mHostLayout = hostLayout;
@@ -75,8 +89,9 @@
 
         processAnimationEvents(mAnimationEvents, finalState);
 
-        boolean hasNewEvents = !mNewEvents.isEmpty();
         int childCount = mHostLayout.getChildCount();
+        mAnimationFilter.applyCombination(mNewEvents);
+        mCurrentLength = NotificationStackScrollLayout.AnimationEvent.combineLength(mNewEvents);
         for (int i = 0; i < childCount; i++) {
             final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
             StackScrollState.ViewState viewState = finalState.getViewStateForView(child);
@@ -84,7 +99,7 @@
                 continue;
             }
 
-            startAnimations(child, viewState, hasNewEvents);
+            startAnimations(child, viewState);
 
             child.setClipBounds(null);
         }
@@ -97,8 +112,7 @@
     /**
      * Start an animation to the given viewState
      */
-    private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState,
-            boolean hasNewEvents) {
+    private void startAnimations(final ExpandableView child, StackScrollState.ViewState viewState) {
         int childVisibility = child.getVisibility();
         boolean wasVisible = childVisibility == View.VISIBLE;
         final float alpha = viewState.alpha;
@@ -107,47 +121,67 @@
         }
         // start translationY animation
         if (child.getTranslationY() != viewState.yTranslation) {
-            startYTranslationAnimation(child, viewState, hasNewEvents);
+            startYTranslationAnimation(child, viewState);
         }
         // start translationZ animation
         if (child.getTranslationZ() != viewState.zTranslation) {
-            startZTranslationAnimation(child, viewState, hasNewEvents);
+            startZTranslationAnimation(child, viewState);
+        }
+        // start scale animation
+        if (child.getScaleX() != viewState.scale) {
+            startScaleAnimation(child, viewState);
         }
         // start alpha animation
         if (alpha != child.getAlpha()) {
-            startAlphaAnimation(child, viewState, hasNewEvents);
+            startAlphaAnimation(child, viewState);
         }
         // start height animation
         if (viewState.height != child.getActualHeight()) {
-            startHeightAnimation(child, viewState, hasNewEvents);
+            startHeightAnimation(child, viewState);
         }
+        // start dimmed animation
+        child.setDimmed(viewState.dimmed, mAnimationFilter.animateDimmed);
     }
 
     private void startHeightAnimation(final ExpandableView child,
-            StackScrollState.ViewState viewState, boolean hasNewEvents) {
-        Integer previousEndValue = getChildTag(child,TAG_END_HEIGHT);
-        if (previousEndValue != null && previousEndValue == viewState.height) {
+            StackScrollState.ViewState viewState) {
+        Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
+        Integer previousEndValue = getChildTag(child, TAG_END_HEIGHT);
+        int newEndValue = viewState.height;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
             return;
         }
         ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_HEIGHT);
-        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, hasNewEvents);
-        if (newDuration <= 0) {
-            // no new animation needed, let's just apply the value
-            child.setActualHeight(viewState.height);
-            if (previousAnimator != null && !isRunning()) {
-                onAnimationFinished();
+        if (!mAnimationFilter.animateHeight) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                int relativeDiff = newEndValue - previousEndValue;
+                int newStartValue = previousStartValue + relativeDiff;
+                values[0].setIntValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_HEIGHT, newStartValue);
+                child.setTag(TAG_END_HEIGHT, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setActualHeight(newEndValue, false);
+                return;
             }
-            return;
         }
 
-        ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), viewState.height);
+        ValueAnimator animator = ValueAnimator.ofInt(child.getActualHeight(), newEndValue);
         animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
-                child.setActualHeight((int) animation.getAnimatedValue());
+                child.setActualHeight((int) animation.getAnimatedValue(),
+                        false /* notifyListeners */);
             }
         });
         animator.setInterpolator(mFastOutSlowInInterpolator);
+        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
         animator.setDuration(newDuration);
         animator.addListener(getGlobalAnimationFinishedListener());
         // remove the tag when the animation is finished
@@ -155,37 +189,49 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 child.setTag(TAG_ANIMATOR_HEIGHT, null);
+                child.setTag(TAG_START_HEIGHT, null);
                 child.setTag(TAG_END_HEIGHT, null);
             }
         });
         startInstantly(animator);
         child.setTag(TAG_ANIMATOR_HEIGHT, animator);
-        child.setTag(TAG_END_HEIGHT, viewState.height);
+        child.setTag(TAG_START_HEIGHT, child.getActualHeight());
+        child.setTag(TAG_END_HEIGHT, newEndValue);
     }
 
     private void startAlphaAnimation(final ExpandableView child,
-            final StackScrollState.ViewState viewState, boolean hasNewEvents) {
-        final float endAlpha = viewState.alpha;
+            final StackScrollState.ViewState viewState) {
+        Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
         Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
-        if (previousEndValue != null && previousEndValue == endAlpha) {
+        final float newEndValue = viewState.alpha;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
             return;
         }
         ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_ALPHA);
-        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, hasNewEvents);
-        if (newDuration <= 0) {
-            // no new animation needed, let's just apply the value
-            child.setAlpha(endAlpha);
-            if (endAlpha == 0) {
-                child.setVisibility(View.INVISIBLE);
+        if (!mAnimationFilter.animateAlpha) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                float relativeDiff = newEndValue - previousEndValue;
+                float newStartValue = previousStartValue + relativeDiff;
+                values[0].setFloatValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_ALPHA, newStartValue);
+                child.setTag(TAG_END_ALPHA, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setAlpha(newEndValue);
+                if (newEndValue == 0) {
+                    child.setVisibility(View.INVISIBLE);
+                }
             }
-            if (previousAnimator != null && !isRunning()) {
-                onAnimationFinished();
-            }
-            return;
         }
 
         ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA,
-                child.getAlpha(), endAlpha);
+                child.getAlpha(), newEndValue);
         animator.setInterpolator(mFastOutSlowInInterpolator);
         // Handle layer type
         final int currentLayerType = child.getLayerType();
@@ -196,10 +242,11 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 child.setLayerType(currentLayerType, null);
-                if (endAlpha == 0 && !mWasCancelled) {
+                if (newEndValue == 0 && !mWasCancelled) {
                     child.setVisibility(View.INVISIBLE);
                 }
                 child.setTag(TAG_ANIMATOR_ALPHA, null);
+                child.setTag(TAG_START_ALPHA, null);
                 child.setTag(TAG_END_ALPHA, null);
             }
 
@@ -213,6 +260,7 @@
                 mWasCancelled = false;
             }
         });
+        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
         animator.setDuration(newDuration);
         animator.addListener(getGlobalAnimationFinishedListener());
         // remove the tag when the animation is finished
@@ -224,30 +272,42 @@
         });
         startInstantly(animator);
         child.setTag(TAG_ANIMATOR_ALPHA, animator);
-        child.setTag(TAG_END_ALPHA, endAlpha);
+        child.setTag(TAG_START_ALPHA, child.getAlpha());
+        child.setTag(TAG_END_ALPHA, newEndValue);
     }
 
     private void startZTranslationAnimation(final ExpandableView child,
-            final StackScrollState.ViewState viewState, boolean hasNewEvents) {
+            final StackScrollState.ViewState viewState) {
+        Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
         Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
-        if (previousEndValue != null && previousEndValue == viewState.zTranslation) {
+        float newEndValue = viewState.zTranslation;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
             return;
         }
         ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Z);
-        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, hasNewEvents);
-        if (newDuration <= 0) {
-            // no new animation needed, let's just apply the value
-            child.setTranslationZ(viewState.zTranslation);
-
-            if (previousAnimator != null && !isRunning()) {
-                onAnimationFinished();
+        if (!mAnimationFilter.animateZ) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                float relativeDiff = newEndValue - previousEndValue;
+                float newStartValue = previousStartValue + relativeDiff;
+                values[0].setFloatValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_TRANSLATION_Z, newStartValue);
+                child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setTranslationZ(newEndValue);
             }
-            return;
         }
 
         ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z,
-                child.getTranslationZ(), viewState.zTranslation);
+                child.getTranslationZ(), newEndValue);
         animator.setInterpolator(mFastOutSlowInInterpolator);
+        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
         animator.setDuration(newDuration);
         animator.addListener(getGlobalAnimationFinishedListener());
         // remove the tag when the animation is finished
@@ -255,34 +315,49 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 child.setTag(TAG_ANIMATOR_TRANSLATION_Z, null);
+                child.setTag(TAG_START_TRANSLATION_Z, null);
                 child.setTag(TAG_END_TRANSLATION_Z, null);
             }
         });
         startInstantly(animator);
         child.setTag(TAG_ANIMATOR_TRANSLATION_Z, animator);
-        child.setTag(TAG_END_TRANSLATION_Z, viewState.zTranslation);
+        child.setTag(TAG_START_TRANSLATION_Z, child.getTranslationZ());
+        child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
     }
 
     private void startYTranslationAnimation(final ExpandableView child,
-            StackScrollState.ViewState viewState, boolean hasNewEvents) {
+            StackScrollState.ViewState viewState) {
+        Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
         Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
-        if (previousEndValue != null && previousEndValue == viewState.yTranslation) {
+        float newEndValue = viewState.yTranslation;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
             return;
         }
         ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y);
-        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator, hasNewEvents);
-        if (newDuration <= 0) {
-            // no new animation needed, let's just apply the value
-            child.setTranslationY(viewState.yTranslation);
-            if (previousAnimator != null && !isRunning()) {
-                onAnimationFinished();
+        if (!mAnimationFilter.animateY) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                float relativeDiff = newEndValue - previousEndValue;
+                float newStartValue = previousStartValue + relativeDiff;
+                values[0].setFloatValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_TRANSLATION_Y, newStartValue);
+                child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setTranslationY(newEndValue);
+                return;
             }
-            return;
         }
 
         ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
-                child.getTranslationY(), viewState.yTranslation);
+                child.getTranslationY(), newEndValue);
         animator.setInterpolator(mFastOutSlowInInterpolator);
+        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
         animator.setDuration(newDuration);
         animator.addListener(getGlobalAnimationFinishedListener());
         // remove the tag when the animation is finished
@@ -290,12 +365,68 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 child.setTag(TAG_ANIMATOR_TRANSLATION_Y, null);
+                child.setTag(TAG_START_TRANSLATION_Y, null);
                 child.setTag(TAG_END_TRANSLATION_Y, null);
             }
         });
         startInstantly(animator);
         child.setTag(TAG_ANIMATOR_TRANSLATION_Y, animator);
-        child.setTag(TAG_END_TRANSLATION_Y, viewState.yTranslation);
+        child.setTag(TAG_START_TRANSLATION_Y, child.getTranslationY());
+        child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
+    }
+
+    private void startScaleAnimation(final ExpandableView child,
+            StackScrollState.ViewState viewState) {
+        Float previousStartValue = getChildTag(child, TAG_START_SCALE);
+        Float previousEndValue = getChildTag(child, TAG_END_SCALE);
+        float newEndValue = viewState.scale;
+        if (previousEndValue != null && previousEndValue == newEndValue) {
+            return;
+        }
+        ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SCALE);
+        if (!mAnimationFilter.animateScale) {
+            // just a local update was performed
+            if (previousAnimator != null) {
+                // we need to increase all animation keyframes of the previous animator by the
+                // relative change to the end value
+                PropertyValuesHolder[] values = previousAnimator.getValues();
+                float relativeDiff = newEndValue - previousEndValue;
+                float newStartValue = previousStartValue + relativeDiff;
+                values[0].setFloatValues(newStartValue, newEndValue);
+                values[1].setFloatValues(newStartValue, newEndValue);
+                child.setTag(TAG_START_SCALE, newStartValue);
+                child.setTag(TAG_END_SCALE, newEndValue);
+                previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+                return;
+            } else {
+                // no new animation needed, let's just apply the value
+                child.setScaleX(newEndValue);
+                child.setScaleY(newEndValue);
+            }
+        }
+
+        PropertyValuesHolder holderX =
+                PropertyValuesHolder.ofFloat(View.SCALE_X, child.getScaleX(), newEndValue);
+        PropertyValuesHolder holderY =
+                PropertyValuesHolder.ofFloat(View.SCALE_Y, child.getScaleY(), newEndValue);
+        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(child, holderX, holderY);
+        animator.setInterpolator(mFastOutSlowInInterpolator);
+        long newDuration = cancelAnimatorAndGetNewDuration(previousAnimator);
+        animator.setDuration(newDuration);
+        animator.addListener(getGlobalAnimationFinishedListener());
+        // remove the tag when the animation is finished
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                child.setTag(TAG_ANIMATOR_SCALE, null);
+                child.setTag(TAG_START_SCALE, null);
+                child.setTag(TAG_END_SCALE, null);
+            }
+        });
+        startInstantly(animator);
+        child.setTag(TAG_ANIMATOR_SCALE, animator);
+        child.setTag(TAG_START_SCALE, child.getScaleX());
+        child.setTag(TAG_END_SCALE, newEndValue);
     }
 
     /**
@@ -349,22 +480,16 @@
      * Cancel the previous animator and get the duration of the new animation.
      *
      * @param previousAnimator the animator which was running before
-     * @param hasNewEvents indicating whether new events came in in this animation
      * @return the new duration
      */
-    private long cancelAnimatorAndGetNewDuration(ValueAnimator previousAnimator,
-            boolean hasNewEvents) {
-        long newDuration = ANIMATION_DURATION;
+    private long cancelAnimatorAndGetNewDuration(ValueAnimator previousAnimator) {
+        long newDuration = mCurrentLength;
         if (previousAnimator != null) {
-            if (!hasNewEvents) {
-                // This is only an update, no new event came in. lets just take the remaining
-                // duration as the new duration
-                newDuration = previousAnimator.getDuration()
-                        - previousAnimator.getCurrentPlayTime();
-            }
+            // We take either the desired length of the new animation or the remaining time of
+            // the previous animator, whichever is longer.
+            newDuration = Math.max(previousAnimator.getDuration()
+                    - previousAnimator.getCurrentPlayTime(), newDuration);
             previousAnimator.cancel();
-        } else if (!hasNewEvents){
-            newDuration = 0;
         }
         return newDuration;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 4b3d3b0..9006c9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -121,11 +121,6 @@
     }
 
     @Override
-    protected int getExpandedViewMaxHeight() {
-        return 0;
-    }
-
-    @Override
     protected boolean shouldDisableNavbarGestures() {
         return true;
     }
@@ -155,4 +150,11 @@
     protected void refreshLayout(int layoutDirection) {
     }
 
+    @Override
+    public void onActivated(View view) {
+    }
+
+    @Override
+    public void onActivationReset(View view) {
+    }
 }
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index dce4f581..a62d1fd 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -63,6 +63,25 @@
     static Method registerNativeAllocation;
     static Method registerNativeFree;
 
+    /*
+     * Context creation flag which specifies a normal context.
+    */
+    public static final long CREATE_FLAG_NONE = 0x0000;
+
+    /*
+     * Context creation flag which specifies a context optimized for low
+     * latency over peak performance. This is a hint and may have no effect
+     * on some implementations.
+    */
+    public static final long CREATE_FLAG_LOW_LATENCY = 0x0001;
+
+    /*
+     * Context creation flag which specifies a context optimized for long
+     * battery life over peak performance. This is a hint and may have no effect
+     * on some implementations.
+    */
+    public static final long CREATE_FLAG_LOW_POWER = 0x0002;
+
     static {
         sInitialized = false;
         if (!SystemProperties.getBoolean("config.disable_renderscript", false)) {
@@ -1145,7 +1164,7 @@
      * @hide
      */
     public static RenderScript create(Context ctx, int sdkVersion) {
-        return create(ctx, sdkVersion, ContextType.NORMAL);
+        return create(ctx, sdkVersion, ContextType.NORMAL, CREATE_FLAG_NONE);
     }
 
     /**
@@ -1155,7 +1174,7 @@
      * @param ctx The context.
      * @return RenderScript
      */
-    public static RenderScript create(Context ctx, int sdkVersion, ContextType ct) {
+    public static RenderScript create(Context ctx, int sdkVersion, ContextType ct, long flags) {
         if (!sInitialized) {
             Log.e(LOG_TAG, "RenderScript.create() called when disabled; someone is likely to crash");
             return null;
@@ -1194,7 +1213,21 @@
      */
     public static RenderScript create(Context ctx, ContextType ct) {
         int v = ctx.getApplicationInfo().targetSdkVersion;
-        return create(ctx, v, ct);
+        return create(ctx, v, ct, CREATE_FLAG_NONE);
+    }
+
+     /**
+     * Create a RenderScript context.
+     *
+     *
+     * @param ctx The context.
+     * @param ct The type of context to be created.
+     * @param flags The OR of the CREATE_FLAG_* options desired
+     * @return RenderScript
+     */
+    public static RenderScript create(Context ctx, ContextType ct, long flags) {
+        int v = ctx.getApplicationInfo().targetSdkVersion;
+        return create(ctx, v, ct, flags);
     }
 
     /**
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index 07933b4..f1ddc07 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -27,7 +27,6 @@
 
 LOCAL_CFLAGS += -Wno-unused-parameter
 
-LOCAL_LDLIBS := -lpthread
 LOCAL_ADDITIONAL_DEPENDENCIES := $(addprefix $(rs_generated_include_dir)/,rsgApiFuncDecl.h)
 LOCAL_MODULE:= librs_jni
 LOCAL_ADDITIONAL_DEPENDENCIES += $(rs_generated_source)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 3619112..4a59a8f 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -38,6 +38,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -197,6 +198,8 @@
 
     private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
 
+    private final UserManager mUserManager;
+
     private int mCurrentUserId = UserHandle.USER_OWNER;
 
     private final LongArray mTempLongArray = new LongArray();
@@ -210,15 +213,6 @@
         return getUserStateLocked(mCurrentUserId);
     }
 
-    private UserState getUserStateLocked(int userId) {
-        UserState state = mUserStates.get(userId);
-        if (state == null) {
-            state = new UserState(userId);
-            mUserStates.put(userId, state);
-        }
-        return state;
-    }
-
     /**
      * Creates a new instance.
      *
@@ -228,6 +222,7 @@
         mContext = context;
         mPackageManager = mContext.getPackageManager();
         mWindowManagerService = LocalServices.getService(WindowManagerInternal.class);
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mSecurityPolicy = new SecurityPolicy();
         mMainHandler = new MainHandler(mContext.getMainLooper());
         registerBroadcastReceivers();
@@ -235,11 +230,22 @@
                 context.getContentResolver());
     }
 
+    private UserState getUserStateLocked(int userId) {
+        UserState state = mUserStates.get(userId);
+        if (state == null) {
+            state = new UserState(userId);
+            mUserStates.put(userId, state);
+        }
+        return state;
+    }
+
     private void registerBroadcastReceivers() {
         PackageMonitor monitor = new PackageMonitor() {
             @Override
             public void onSomePackagesChanged() {
                 synchronized (mLock) {
+                    // Only the profile parent can install accessibility services.
+                    // Therefore we ignore packages from linked profiles.
                     if (getChangingUserId() != mCurrentUserId) {
                         return;
                     }
@@ -262,6 +268,8 @@
             public void onPackageRemoved(String packageName, int uid) {
                 synchronized (mLock) {
                     final int userId = getChangingUserId();
+                    // Only the profile parent can install accessibility services.
+                    // Therefore we ignore packages from linked profiles.
                     if (userId != mCurrentUserId) {
                         return;
                     }
@@ -297,6 +305,8 @@
                     int uid, boolean doit) {
                 synchronized (mLock) {
                     final int userId = getChangingUserId();
+                    // Only the profile parent can install accessibility services.
+                    // Therefore we ignore packages from linked profiles.
                     if (userId != mCurrentUserId) {
                         return false;
                     }
@@ -359,6 +369,9 @@
     @Override
     public int addClient(IAccessibilityManagerClient client, int userId) {
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             // If the client is from a process that runs across users such as
@@ -388,6 +401,9 @@
     @Override
     public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) {
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution..
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             // This method does nothing for a background user.
@@ -414,6 +430,9 @@
     @Override
     public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             // The automation service is a fake one and should not be reported
@@ -435,6 +454,9 @@
             int userId) {
         List<AccessibilityServiceInfo> result = null;
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
 
@@ -468,6 +490,9 @@
     public void interrupt(int userId) {
         CopyOnWriteArrayList<Service> services;
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             // This method does nothing for a background user.
@@ -491,6 +516,9 @@
     public int addAccessibilityInteractionConnection(IWindow windowToken,
             IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
             final int windowId = sNextWindowId++;
@@ -527,6 +555,9 @@
     @Override
     public void removeAccessibilityInteractionConnection(IWindow window) {
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
             mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
                     UserHandle.getCallingUserId());
             IBinder token = window.asBinder();
@@ -675,6 +706,9 @@
                 Manifest.permission.RETRIEVE_WINDOW_TOKEN,
                 GET_WINDOW_TOKEN);
         synchronized (mLock) {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(
                             UserHandle.getCallingUserId());
@@ -770,7 +804,7 @@
             }
 
             // Disconnect from services for the old user.
-            UserState oldUserState = getUserStateLocked(mCurrentUserId);
+            UserState oldUserState = getCurrentUserStateLocked();
             oldUserState.onSwitchToAnotherUser();
 
             // Disable the local managers for the old user.
@@ -2034,6 +2068,9 @@
         @Override
         public List<AccessibilityWindowInfo> getWindows() {
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its perent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
                                 UserHandle.getCallingUserId());
@@ -2062,6 +2099,9 @@
         @Override
         public AccessibilityWindowInfo getWindow(int windowId) {
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
                                 UserHandle.getCallingUserId());
@@ -2092,6 +2132,9 @@
             final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
                                 UserHandle.getCallingUserId());
@@ -2136,9 +2179,12 @@
             final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
-                        UserHandle.getCallingUserId());
+                                UserHandle.getCallingUserId());
                 if (resolvedUserId != mCurrentUserId) {
                     return false;
                 }
@@ -2180,9 +2226,12 @@
             final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
-                        UserHandle.getCallingUserId());
+                                UserHandle.getCallingUserId());
                 if (resolvedUserId != mCurrentUserId) {
                     return false;
                 }
@@ -2224,9 +2273,12 @@
             final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
-                        UserHandle.getCallingUserId());
+                                UserHandle.getCallingUserId());
                 if (resolvedUserId != mCurrentUserId) {
                     return false;
                 }
@@ -2268,9 +2320,12 @@
             final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
-                        UserHandle.getCallingUserId());
+                                UserHandle.getCallingUserId());
                 if (resolvedUserId != mCurrentUserId) {
                     return false;
                 }
@@ -2311,9 +2366,12 @@
             final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
-                        UserHandle.getCallingUserId());
+                                UserHandle.getCallingUserId());
                 if (resolvedUserId != mCurrentUserId) {
                     return false;
                 }
@@ -2346,9 +2404,12 @@
 
         public boolean performGlobalAction(int action) {
             synchronized (mLock) {
+                // We treat calls from a profile as if made by its parent as profiles
+                // share the accessibility state of the parent. The call below
+                // performs the current profile parent resolution.
                 final int resolvedUserId = mSecurityPolicy
                         .resolveCallingUserIdEnforcingPermissionsLocked(
-                        UserHandle.getCallingUserId());
+                                UserHandle.getCallingUserId());
                 if (resolvedUserId != mCurrentUserId) {
                     return false;
                 }
@@ -3407,16 +3468,35 @@
                     & AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
         }
 
+        private int resolveProfileParentLocked(int userId) {
+            if (userId != mCurrentUserId) {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    UserInfo parent = mUserManager.getProfileParent(userId);
+                    if (parent != null) {
+                        return parent.getUserHandle().getIdentifier();
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+            return userId;
+        }
+
         public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) {
             final int callingUid = Binder.getCallingUid();
             if (callingUid == 0
                     || callingUid == Process.SYSTEM_UID
                     || callingUid == Process.SHELL_UID) {
-                return mCurrentUserId;
+                if (userId == UserHandle.USER_CURRENT
+                        || userId == UserHandle.USER_CURRENT_OR_SELF) {
+                    return mCurrentUserId;
+                }
+                return resolveProfileParentLocked(userId);
             }
             final int callingUserId = UserHandle.getUserId(callingUid);
             if (callingUserId == userId) {
-                return userId;
+                return resolveProfileParentLocked(userId);
             }
             if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS)
                     && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) {
@@ -3673,8 +3753,10 @@
         public void onChange(boolean selfChange, Uri uri) {
             if (mAccessibilityEnabledUri.equals(uri)) {
                 synchronized (mLock) {
-                    // We will update when the automation service dies.
+                    // Profiles share the accessibility state of the parent. Therefore,
+                    // we are checking for changes only the parent settings.
                     UserState userState = getCurrentUserStateLocked();
+                    // We will update when the automation service dies.
                     if (userState.mUiAutomationService == null) {
                         if (readAccessibilityEnabledSettingLocked(userState)) {
                             onUserStateChangedLocked(userState);
@@ -3683,8 +3765,10 @@
                 }
             } else if (mTouchExplorationEnabledUri.equals(uri)) {
                 synchronized (mLock) {
-                    // We will update when the automation service dies.
+                    // Profiles share the accessibility state of the parent. Therefore,
+                    // we are checking for changes only the parent settings.
                     UserState userState = getCurrentUserStateLocked();
+                    // We will update when the automation service dies.
                     if (userState.mUiAutomationService == null) {
                         if (readTouchExplorationEnabledSettingLocked(userState)) {
                             onUserStateChangedLocked(userState);
@@ -3693,8 +3777,10 @@
                 }
             } else if (mDisplayMagnificationEnabledUri.equals(uri)) {
                 synchronized (mLock) {
-                    // We will update when the automation service dies.
+                    // Profiles share the accessibility state of the parent. Therefore,
+                    // we are checking for changes only the parent settings.
                     UserState userState = getCurrentUserStateLocked();
+                    // We will update when the automation service dies.
                     if (userState.mUiAutomationService == null) {
                         if (readDisplayMagnificationEnabledSettingLocked(userState)) {
                             onUserStateChangedLocked(userState);
@@ -3703,8 +3789,10 @@
                 }
             } else if (mEnabledAccessibilityServicesUri.equals(uri)) {
                 synchronized (mLock) {
-                    // We will update when the automation service dies.
+                    // Profiles share the accessibility state of the parent. Therefore,
+                    // we are checking for changes only the parent settings.
                     UserState userState = getCurrentUserStateLocked();
+                    // We will update when the automation service dies.
                     if (userState.mUiAutomationService == null) {
                         if (readEnabledAccessibilityServicesLocked(userState)) {
                             onUserStateChangedLocked(userState);
@@ -3713,8 +3801,10 @@
                 }
             } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
                 synchronized (mLock) {
-                    // We will update when the automation service dies.
+                    // Profiles share the accessibility state of the parent. Therefore,
+                    // we are checking for changes only the parent settings.
                     UserState userState = getCurrentUserStateLocked();
+                    // We will update when the automation service dies.
                     if (userState.mUiAutomationService == null) {
                         if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) {
                             onUserStateChangedLocked(userState);
@@ -3723,8 +3813,10 @@
                 }
             } else if (mEnhancedWebAccessibilityUri.equals(uri)) {
                 synchronized (mLock) {
-                    // We will update when the automation service dies.
+                    // Profiles share the accessibility state of the parent. Therefore,
+                    // we are checking for changes only the parent settings.
                     UserState userState = getCurrentUserStateLocked();
+                    // We will update when the automation service dies.
                     if (userState.mUiAutomationService == null) {
                         if (readEnhancedWebAccessibilityEnabledChangedLocked(userState)) {
                             onUserStateChangedLocked(userState);
@@ -3739,8 +3831,10 @@
                     || mDisplayInversionUri.equals(uri)
                     || mDisplayDaltonizerUri.equals(uri)) {
                 synchronized (mLock) {
-                    // We will update when the automation service dies.
+                    // Profiles share the accessibility state of the parent. Therefore,
+                    // we are checking for changes only the parent settings.
                     UserState userState = getCurrentUserStateLocked();
+                    // We will update when the automation service dies.
                     if (userState.mUiAutomationService == null) {
                         if (readDisplayColorAdjustmentSettingsLocked(userState)) {
                             updateDisplayColorAdjustmentSettingsLocked(userState);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 45cdb65..dfffa8a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -74,7 +74,7 @@
 import android.net.NetworkUtils;
 import android.net.Proxy;
 import android.net.ProxyDataTracker;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
 import android.net.RouteInfo;
 import android.net.SamplingDataTracker;
 import android.net.Uri;
@@ -406,12 +406,12 @@
     private ArrayList mInetLog;
 
     // track the current default http proxy - tell the world if we get a new one (real change)
-    private ProxyProperties mDefaultProxy = null;
+    private ProxyInfo mDefaultProxy = null;
     private Object mProxyLock = new Object();
     private boolean mDefaultProxyDisabled = false;
 
     // track the global proxy.
-    private ProxyProperties mGlobalProxy = null;
+    private ProxyInfo mGlobalProxy = null;
 
     private PacManager mPacManager = null;
 
@@ -3192,7 +3192,7 @@
                     break;
                 }
                 case EVENT_PROXY_HAS_CHANGED: {
-                    handleApplyDefaultProxy((ProxyProperties)msg.obj);
+                    handleApplyDefaultProxy((ProxyInfo)msg.obj);
                     break;
                 }
             }
@@ -3410,19 +3410,19 @@
         return;
     }
 
-    public ProxyProperties getProxy() {
+    public ProxyInfo getProxy() {
         // this information is already available as a world read/writable jvm property
         // so this API change wouldn't have a benifit.  It also breaks the passing
         // of proxy info to all the JVMs.
         // enforceAccessPermission();
         synchronized (mProxyLock) {
-            ProxyProperties ret = mGlobalProxy;
+            ProxyInfo ret = mGlobalProxy;
             if ((ret == null) && !mDefaultProxyDisabled) ret = mDefaultProxy;
             return ret;
         }
     }
 
-    public void setGlobalProxy(ProxyProperties proxyProperties) {
+    public void setGlobalProxy(ProxyInfo proxyProperties) {
         enforceConnectivityInternalPermission();
 
         synchronized (mProxyLock) {
@@ -3435,18 +3435,18 @@
             String exclList = "";
             String pacFileUrl = "";
             if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) ||
-                    !TextUtils.isEmpty(proxyProperties.getPacFileUrl()))) {
+                    (proxyProperties.getPacFileUrl() != null))) {
                 if (!proxyProperties.isValid()) {
                     if (DBG)
                         log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
                     return;
                 }
-                mGlobalProxy = new ProxyProperties(proxyProperties);
+                mGlobalProxy = new ProxyInfo(proxyProperties);
                 host = mGlobalProxy.getHost();
                 port = mGlobalProxy.getPort();
-                exclList = mGlobalProxy.getExclusionList();
+                exclList = mGlobalProxy.getExclusionListAsString();
                 if (proxyProperties.getPacFileUrl() != null) {
-                    pacFileUrl = proxyProperties.getPacFileUrl();
+                    pacFileUrl = proxyProperties.getPacFileUrl().toString();
                 }
             } else {
                 mGlobalProxy = null;
@@ -3478,11 +3478,11 @@
                 Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
         String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC);
         if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
-            ProxyProperties proxyProperties;
+            ProxyInfo proxyProperties;
             if (!TextUtils.isEmpty(pacFileUrl)) {
-                proxyProperties = new ProxyProperties(pacFileUrl);
+                proxyProperties = new ProxyInfo(pacFileUrl);
             } else {
-                proxyProperties = new ProxyProperties(host, port, exclList);
+                proxyProperties = new ProxyInfo(host, port, exclList);
             }
             if (!proxyProperties.isValid()) {
                 if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
@@ -3495,7 +3495,7 @@
         }
     }
 
-    public ProxyProperties getGlobalProxy() {
+    public ProxyInfo getGlobalProxy() {
         // this information is already available as a world read/writable jvm property
         // so this API change wouldn't have a benifit.  It also breaks the passing
         // of proxy info to all the JVMs.
@@ -3505,9 +3505,9 @@
         }
     }
 
-    private void handleApplyDefaultProxy(ProxyProperties proxy) {
+    private void handleApplyDefaultProxy(ProxyInfo proxy) {
         if (proxy != null && TextUtils.isEmpty(proxy.getHost())
-                && TextUtils.isEmpty(proxy.getPacFileUrl())) {
+                && (proxy.getPacFileUrl() == null)) {
             proxy = null;
         }
         synchronized (mProxyLock) {
@@ -3517,6 +3517,18 @@
                 if (DBG) log("Invalid proxy properties, ignoring: " + proxy.toString());
                 return;
             }
+
+            // This call could be coming from the PacManager, containing the port of the local
+            // proxy.  If this new proxy matches the global proxy then copy this proxy to the
+            // global (to get the correct local port), and send a broadcast.
+            // TODO: Switch PacManager to have its own message to send back rather than
+            // reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy.
+            if ((mGlobalProxy != null) && (proxy != null) && (proxy.getPacFileUrl() != null)
+                    && proxy.getPacFileUrl().equals(mGlobalProxy.getPacFileUrl())) {
+                mGlobalProxy = proxy;
+                sendProxyBroadcast(mGlobalProxy);
+                return;
+            }
             mDefaultProxy = proxy;
 
             if (mGlobalProxy != null) return;
@@ -3544,13 +3556,13 @@
                     return;
                 }
             }
-            ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
+            ProxyInfo p = new ProxyInfo(data[0], proxyPort, "");
             setGlobalProxy(p);
         }
     }
 
-    private void sendProxyBroadcast(ProxyProperties proxy) {
-        if (proxy == null) proxy = new ProxyProperties("", 0, "");
+    private void sendProxyBroadcast(ProxyInfo proxy) {
+        if (proxy == null) proxy = new ProxyInfo("", 0, "");
         if (mPacManager.setCurrentProxyScriptUrl(proxy)) return;
         if (DBG) log("sending Proxy Broadcast for " + proxy);
         Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 7ec9b82..d5f045e 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -201,8 +201,8 @@
     public static final String[] CRYPTO_TYPES
         = { "password", "default", "pattern", "pin" };
 
-    private Context mContext;
-    private NativeDaemonConnector mConnector;
+    private final Context mContext;
+    private final NativeDaemonConnector mConnector;
 
     private final Object mVolumesLock = new Object();
 
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 132ca00..82c13e0 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -41,6 +41,7 @@
 import android.provider.Settings.SettingNotFoundException;
 import android.util.Slog;
 import android.view.InputDevice;
+import android.media.AudioManager;
 
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
@@ -73,6 +74,8 @@
     private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
 
     private int mCurVibUid = -1;
+    private boolean mLowPowerMode;
+    private SettingsObserver mSettingObserver;
 
     native static boolean vibratorExists();
     native static void vibratorOn(long milliseconds);
@@ -159,15 +162,15 @@
 
     public void systemReady() {
         mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE);
+        mSettingObserver = new SettingsObserver(mH);
 
         mContext.getContentResolver().registerContentObserver(
-                Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), true,
-                new ContentObserver(mH) {
-                    @Override
-                    public void onChange(boolean selfChange) {
-                        updateInputDeviceVibrators();
-                    }
-                }, UserHandle.USER_ALL);
+                Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
+                true, mSettingObserver, UserHandle.USER_ALL);
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE), false,
+                mSettingObserver, UserHandle.USER_ALL);
 
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
@@ -179,6 +182,17 @@
         updateInputDeviceVibrators();
     }
 
+    private final class SettingsObserver extends ContentObserver {
+        public SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean SelfChange) {
+            updateInputDeviceVibrators();
+        }
+    }
+
     public boolean hasVibrator() {
         return doVibratorExists();
     }
@@ -346,6 +360,10 @@
     // Lock held on mVibrations
     private void startVibrationLocked(final Vibration vib) {
         try {
+            if (mLowPowerMode && vib.mStreamHint != AudioManager.STREAM_RING) {
+                return;
+            }
+
             int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
                     vib.mStreamHint, vib.mUid, vib.mOpPkg);
             if (mode == AppOpsManager.MODE_ALLOWED) {
@@ -425,6 +443,9 @@
                 } catch (SettingNotFoundException snfe) {
                 }
 
+                mLowPowerMode = Settings.Global.getInt(mContext.getContentResolver(),
+                         Settings.Global.LOW_POWER_MODE, 0) != 0;
+
                 if (mVibrateInputDevicesSetting) {
                     if (!mInputDeviceListenerRegistered) {
                         mInputDeviceListenerRegistered = true;
diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java
index 50cfe48..c32beda 100644
--- a/services/core/java/com/android/server/WiredAccessoryManager.java
+++ b/services/core/java/com/android/server/WiredAccessoryManager.java
@@ -70,6 +70,7 @@
     private static final String NAME_HDMI = "hdmi";
 
     private static final int MSG_NEW_DEVICE_STATE = 1;
+    private static final int MSG_SYSTEM_READY = 2;
 
     private final Object mLock = new Object();
 
@@ -96,19 +97,9 @@
                 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
 
         mObserver = new WiredAccessoryObserver();
-
-        IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
-        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
-        context.registerReceiver(new BroadcastReceiver() {
-                    @Override
-                    public void onReceive(Context ctx, Intent intent) {
-                        bootCompleted();
-                    }
-                },
-                filter, null, null);
     }
 
-    private void bootCompleted() {
+    private void onSystemReady() {
         if (mUseDevInputEventForAudioJack) {
             int switchValues = 0;
             if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) {
@@ -159,6 +150,16 @@
         }
     }
 
+    @Override
+    public void systemReady() {
+        synchronized (mLock) {
+            mWakeLock.acquire();
+
+            Message msg = mHandler.obtainMessage(MSG_SYSTEM_READY, 0, 0, null);
+            mHandler.sendMessage(msg);
+        }
+    }
+
     /**
      * Compare the existing headset state with the new state and pass along accordingly. Note
      * that this only supports a single headset at a time. Inserting both a usb and jacked headset
@@ -220,6 +221,11 @@
                 case MSG_NEW_DEVICE_STATE:
                     setDevicesState(msg.arg1, msg.arg2, (String)msg.obj);
                     mWakeLock.release();
+                    break;
+                case MSG_SYSTEM_READY:
+                    onSystemReady();
+                    mWakeLock.release();
+                    break;
             }
         }
     };
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cbb8377..5358c1a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -35,6 +35,7 @@
 import android.appwidget.AppWidgetManager;
 import android.graphics.Rect;
 import android.os.BatteryStats;
+import android.os.PersistableBundle;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArrayMap;
 
@@ -136,7 +137,7 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.net.Proxy;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
@@ -983,7 +984,7 @@
 
     /**
      * This is set if we had to do a delayed dexopt of an app before launching
-     * it, to increasing the ANR timeouts in that case.
+     * it, to increase the ANR timeouts in that case.
      */
     boolean mDidDexOpt;
 
@@ -1323,16 +1324,18 @@
                 }
             } break;
             case UPDATE_HTTP_PROXY_MSG: {
-                ProxyProperties proxy = (ProxyProperties)msg.obj;
+                ProxyInfo proxy = (ProxyInfo)msg.obj;
                 String host = "";
                 String port = "";
                 String exclList = "";
-                String pacFileUrl = null;
+                String pacFileUrl = "";
                 if (proxy != null) {
                     host = proxy.getHost();
                     port = Integer.toString(proxy.getPort());
-                    exclList = proxy.getExclusionList();
-                    pacFileUrl = proxy.getPacFileUrl();
+                    exclList = proxy.getExclusionListAsString();
+                    if (proxy.getPacFileUrl() != null) {
+                        pacFileUrl = proxy.getPacFileUrl().toString();
+                    }
                 }
                 synchronized (ActivityManagerService.this) {
                     for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
@@ -1850,6 +1853,12 @@
 
         @Override
         public boolean onPackageChanged(String packageName, int uid, String[] components) {
+            onPackageModified(packageName);
+            return true;
+        }
+
+        @Override
+        public void onPackageModified(String packageName) {
             final PackageManager pm = mContext.getPackageManager();
             final ArrayList<Pair<Intent, Integer>> recentTaskIntents =
                     new ArrayList<Pair<Intent, Integer>>();
@@ -1885,7 +1894,6 @@
                     removeTaskByIdLocked(tasksToRemove.get(i), 0);
                 }
             }
-            return true;
         }
 
         @Override
@@ -5422,22 +5430,21 @@
     }
 
     @Override
-    public final void activityPaused(IBinder token) {
+    public final void activityPaused(IBinder token, PersistableBundle persistentState) {
         final long origId = Binder.clearCallingIdentity();
         synchronized(this) {
             ActivityStack stack = ActivityRecord.getStackLocked(token);
             if (stack != null) {
-                stack.activityPausedLocked(token, false);
+                stack.activityPausedLocked(token, false, persistentState);
             }
         }
         Binder.restoreCallingIdentity(origId);
     }
 
     @Override
-    public final void activityStopped(IBinder token, Bundle icicle, Bitmap thumbnail,
-            CharSequence description) {
-        if (localLOGV) Slog.v(
-            TAG, "Activity stopped: token=" + token);
+    public final void activityStopped(IBinder token, Bundle icicle,
+            PersistableBundle persistentState, CharSequence description) {
+        if (localLOGV) Slog.v(TAG, "Activity stopped: token=" + token);
 
         // Refuse possible leaked file descriptors
         if (icicle != null && icicle.hasFileDescriptors()) {
@@ -5449,7 +5456,7 @@
         synchronized (this) {
             ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
-                r.task.stack.activityStoppedLocked(r, icicle, thumbnail, description);
+                r.task.stack.activityStoppedLocked(r, icicle, persistentState, description);
             }
         }
 
@@ -9565,6 +9572,7 @@
             }
 
             mAppOpsService.systemReady();
+            mUsageStatsService.systemReady();
             mSystemReady = true;
         }
 
@@ -13758,7 +13766,7 @@
         }
 
         if (Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) {
-            ProxyProperties proxy = intent.getParcelableExtra("proxy");
+            ProxyInfo proxy = intent.getParcelableExtra("proxy");
             mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
         }
 
@@ -14386,6 +14394,7 @@
                 newConfig.seq = mConfigurationSeq;
                 mConfiguration = newConfig;
                 Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + newConfig);
+                mUsageStatsService.noteStartConfig(newConfig);
 
                 final Configuration configCopy = new Configuration(mConfiguration);
                 
@@ -16523,7 +16532,7 @@
                 }
 
                 if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
-                    if (userId != 0) {
+                    if (userId != UserHandle.USER_OWNER) {
                         Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
                         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                         broadcastIntentLocked(null, null, intent, null,
@@ -16552,6 +16561,8 @@
                     EventLogTags.writeAmSwitchUser(userId);
                     getUserManagerLocked().userForeground(userId);
                     sendUserSwitchBroadcastsLocked(oldUserId, userId);
+                } else {
+                    mStackSupervisor.startBackgroundUserLocked(userId, uss);
                 }
 
                 if (needStart) {
@@ -16727,7 +16738,7 @@
         }
     }
 
-    void finishUserSwitch(UserStartedState uss) {
+    void finishUserBoot(UserStartedState uss) {
         synchronized (this) {
             if (uss.mState == UserStartedState.STATE_BOOTING
                     && mStartedUsers.get(uss.mHandle.getIdentifier()) == uss) {
@@ -16741,6 +16752,12 @@
                         android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE,
                         true, false, MY_PID, Process.SYSTEM_UID, userId);
             }
+        }
+    }
+
+    void finishUserSwitch(UserStartedState uss) {
+        synchronized (this) {
+            finishUserBoot(uss);
 
             startProfilesLocked();
 
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 7c3f288..8391f79 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -16,8 +16,8 @@
 
 package com.android.server.am;
 
+import android.os.PersistableBundle;
 import android.os.Trace;
-import com.android.internal.R.styleable;
 import com.android.internal.app.ResolverActivity;
 import com.android.server.AttributeCache;
 import com.android.server.am.ActivityStack.ActivityState;
@@ -118,6 +118,7 @@
     ProcessRecord app;      // if non-null, hosting application
     ActivityState state;    // current state we are in
     Bundle  icicle;         // last saved activity state
+    PersistableBundle persistentState; // last persistently saved activity state
     boolean frontOfTask;    // is this the root activity of its task?
     boolean launchFailed;   // set if a launched failed, to abort on 2nd try
     boolean haveState;      // have we gotten the last activity state?
@@ -480,7 +481,7 @@
     void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) {
         if (task != null && task.removeActivity(this)) {
             if (task != newTask) {
-                task.stack.removeTask(task, false);
+                task.stack.removeTask(task);
             } else {
                 Slog.d(TAG, "!!! REMOVE THIS LOG !!! setTask: nearly removed stack=" +
                         (newTask == null ? null : newTask.stack));
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ee39b67..7c29d85 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -36,8 +36,6 @@
 import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES;
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 
-import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.CONTAINER_STATE_HAS_SURFACE;
-
 import android.service.voice.IVoiceInteractionSession;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.BatteryStatsImpl;
@@ -70,6 +68,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
@@ -278,7 +277,7 @@
                         if (r.app != null) {
                             mService.logAppTooSlow(r.app, r.pauseTime, "pausing " + r);
                         }
-                        activityPausedLocked(r.appToken, true);
+                        activityPausedLocked(r.appToken, true, r.persistentState);
                     }
                 } break;
                 case LAUNCH_TICK_MSG: {
@@ -862,13 +861,15 @@
         }
     }
 
-    final void activityPausedLocked(IBinder token, boolean timeout) {
+    final void activityPausedLocked(IBinder token, boolean timeout,
+            PersistableBundle persistentState) {
         if (DEBUG_PAUSE) Slog.v(
             TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
 
         final ActivityRecord r = isInStackLocked(token);
         if (r != null) {
             mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
+            r.persistentState = persistentState;
             if (mPausingActivity == r) {
                 if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
                         + (timeout ? " (due to timeout)" : " (pause complete)"));
@@ -883,13 +884,14 @@
         }
     }
 
-    final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
-            CharSequence description) {
+    final void activityStoppedLocked(ActivityRecord r, Bundle icicle,
+            PersistableBundle persistentState, CharSequence description) {
         if (r.state != ActivityState.STOPPING) {
             Slog.i(TAG, "Activity reported stop, but no longer stopping: " + r);
             mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
             return;
         }
+        r.persistentState = persistentState;
         if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle);
         if (icicle != null) {
             // If icicle is null, this is happening due to a timeout, so we
@@ -897,7 +899,7 @@
             r.icicle = icicle;
             r.haveState = true;
             r.launchCount = 0;
-            r.updateThumbnail(thumbnail, description);
+            r.updateThumbnail(null, description);
         }
         if (!r.stopped) {
             if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)");
@@ -1082,20 +1084,6 @@
         }
     }
 
-    /**
-     * Version of ensureActivitiesVisible that can easily be called anywhere.
-     */
-    final boolean ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
-        return ensureActivitiesVisibleLocked(starting, configChanges, false);
-    }
-
-    final boolean ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges,
-            boolean forceHomeShown) {
-        ActivityRecord r = topRunningActivityLocked(null);
-        return r != null &&
-                ensureActivitiesVisibleLocked(r, starting, null, configChanges, forceHomeShown);
-    }
-
     // Checks if any of the stacks above this one has a fullscreen activity behind it.
     // If so, this stack is hidden, otherwise it is visible.
     private boolean isStackVisible() {
@@ -1107,16 +1095,26 @@
             return true;
         }
 
-        // Start at the task above this one and go up, looking for a visible
-        // fullscreen activity, or a translucent activity that requested the
-        // wallpaper to be shown behind it.
+        /**
+         * Start at the task above this one and go up, looking for a visible
+         * fullscreen activity, or a translucent activity that requested the
+         * wallpaper to be shown behind it.
+         */
         for (int i = mStacks.indexOf(this) + 1; i < mStacks.size(); i++) {
             final ArrayList<TaskRecord> tasks = mStacks.get(i).getAllTasks();
             for (int taskNdx = 0; taskNdx < tasks.size(); taskNdx++) {
                 final ArrayList<ActivityRecord> activities = tasks.get(taskNdx).mActivities;
                 for (int activityNdx = 0; activityNdx < activities.size(); activityNdx++) {
                     final ActivityRecord r = activities.get(activityNdx);
-                    if (!r.finishing && r.visible && r.fullscreen) {
+
+                    // Conditions for an activity to obscure the stack we're
+                    // examining:
+                    // 1. Not Finishing AND Visible AND:
+                    // 2. Either:
+                    // - Full Screen Activity OR
+                    // - On top of Home and our stack is NOT home
+                    if (!r.finishing && r.visible && (r.fullscreen ||
+                            (!isHomeStack() && r.frontOfTask && tasks.get(taskNdx).mOnTopOfHome))) {
                         return false;
                     }
                 }
@@ -1126,12 +1124,19 @@
         return true;
     }
 
+    final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
+        ActivityRecord r = topRunningActivityLocked(null);
+        if (r != null) {
+            ensureActivitiesVisibleLocked(r, starting, null, configChanges);
+        }
+    }
+
     /**
      * Make sure that all activities that need to be visible (that is, they
      * currently can be seen by the user) actually are.
      */
-    final boolean ensureActivitiesVisibleLocked(ActivityRecord top, ActivityRecord starting,
-            String onlyThisProcess, int configChanges, boolean forceHomeShown) {
+    final void ensureActivitiesVisibleLocked(ActivityRecord top, ActivityRecord starting,
+            String onlyThisProcess, int configChanges) {
         if (DEBUG_VISBILITY) Slog.v(
                 TAG, "ensureActivitiesVisible behind " + top
                 + " configChanges=0x" + Integer.toHexString(configChanges));
@@ -1149,7 +1154,6 @@
         // If the top activity is not fullscreen, then we need to
         // make sure any activities under it are now visible.
         boolean aboveTop = true;
-        boolean showHomeBehindStack = false;
         boolean behindFullscreen = !isStackVisible();
 
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -1237,11 +1241,9 @@
                         // At this point, nothing else needs to be shown
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
                         behindFullscreen = true;
-                        showHomeBehindStack = false;
-                    } else if (isActivityOverHome(r)) {
+                    } else if (!isHomeStack() && r.frontOfTask && task.mOnTopOfHome) {
                         if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
-                        showHomeBehindStack = true;
-                        behindFullscreen = !isHomeStack() && r.frontOfTask && task.mOnTopOfHome;
+                        behindFullscreen = true;
                     }
                 } else {
                     if (DEBUG_VISBILITY) Slog.v(
@@ -1291,7 +1293,6 @@
                 }
             }
         }
-        return showHomeBehindStack;
     }
 
     void convertToTranslucent(ActivityRecord r) {
@@ -2841,7 +2842,7 @@
             if (mStackSupervisor.isFrontStack(this) && task == topTask() && task.mOnTopOfHome) {
                 mStackSupervisor.moveHomeToTop();
             }
-            removeTask(task, false);
+            removeTask(task);
         }
         cleanUpActivityServicesLocked(r);
         r.removeUriPermissionsLocked();
@@ -3717,7 +3718,7 @@
         return starting;
     }
 
-    void removeTask(TaskRecord task, boolean moving) {
+    void removeTask(TaskRecord task) {
         mStackSupervisor.endLockTaskModeIfTaskEnding(task);
         mWindowManager.removeTask(task.taskId);
         final ActivityRecord r = mResumedActivity;
@@ -3731,14 +3732,20 @@
             mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
         }
         mTaskHistory.remove(task);
-        if (!moving && task.voiceSession != null) {
-            // This task was a voice interaction, so it should not remain on the
-            // recent tasks list.
-            try {
-                task.voiceSession.taskFinished(task.intent, task.taskId);
-            } catch (RemoteException e) {
+
+        if (task.mActivities.isEmpty()) {
+            final boolean isVoiceSession = task.voiceSession != null;
+            if (isVoiceSession) {
+                try {
+                    task.voiceSession.taskFinished(task.intent, task.taskId);
+                } catch (RemoteException e) {
+                }
             }
-            mService.mRecentTasks.remove(task);
+            if (task.autoRemoveFromRecents() || isVoiceSession) {
+                // Task creator asked to remove this when done, or this task was a voice
+                // interaction, so it should not remain on the recent tasks list.
+                mService.mRecentTasks.remove(task);
+            }
         }
 
         if (mTaskHistory.isEmpty()) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 2e979d2..6f62a03 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -193,6 +193,9 @@
     /** Used on user changes */
     final ArrayList<UserStartedState> mStartingUsers = new ArrayList<UserStartedState>();
 
+    /** Used to queue up any background users being started */
+    final ArrayList<UserStartedState> mStartingBackgroundUsers = new ArrayList<UserStartedState>();
+
     /** Set to indicate whether to issue an onUserLeaving callback when a newly launched activity
      * is being brought in front of us. */
     boolean mUserLeaving = false;
@@ -1023,10 +1026,10 @@
             r.clearOptionsLocked();
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                     System.identityHashCode(r), r.info,
-                    new Configuration(mService.mConfiguration), r.compat,
-                    r.task.voiceInteractor, app.repProcState, r.icicle, results, newIntents,
-                    !andResume, mService.isNextTransitionForward(), profileFile, profileFd,
-                    profileAutoStop, options);
+                    new Configuration(mService.mConfiguration), r.compat, r.task.voiceInteractor,
+                    app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume,
+                    mService.isNextTransitionForward(), profileFile, profileFd, profileAutoStop,
+                    options);
 
             if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
                 // This may be a heavy-weight process!  Note that the package
@@ -1471,6 +1474,17 @@
             }
         }
 
+        switch (r.info.documentLaunchMode) {
+            case ActivityInfo.DOCUMENT_LAUNCH_NONE:
+                break;
+            case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
+                intent.addFlags(
+                        Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+                break;
+            case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+                break;
+        }
         final boolean newDocument = intent.isDocument();
         if (sourceRecord == null) {
             // This activity is not being started from another...  in this
@@ -1988,9 +2002,20 @@
 
         if (booting) {
             mService.finishBooting();
-        } else if (startingUsers != null) {
-            for (int i = 0; i < startingUsers.size(); i++) {
-                mService.finishUserSwitch(startingUsers.get(i));
+        } else {
+            // Complete user switch
+            if (startingUsers != null) {
+                for (int i = 0; i < startingUsers.size(); i++) {
+                    mService.finishUserSwitch(startingUsers.get(i));
+                }
+            }
+            // Complete starting up of background users
+            if (mStartingBackgroundUsers.size() > 0) {
+                startingUsers = new ArrayList<UserStartedState>(mStartingBackgroundUsers);
+                mStartingBackgroundUsers.clear();
+                for (int i = 0; i < startingUsers.size(); i++) {
+                    mService.finishUserBoot(startingUsers.get(i));
+                }
             }
         }
 
@@ -2237,7 +2262,7 @@
             Slog.w(TAG, "moveTaskToStack: no stack for id=" + stackId);
             return;
         }
-        task.stack.removeTask(task, true);
+        task.stack.removeTask(task);
         stack.addTask(task, toTop, true);
         mWindowManager.addTask(taskId, stackId, toTop);
         resumeTopActivitiesLocked();
@@ -2430,21 +2455,12 @@
 
     void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges) {
         // First the front stacks. In case any are not fullscreen and are in front of home.
-        boolean showHomeBehindStack = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             final int topStackNdx = stacks.size() - 1;
             for (int stackNdx = topStackNdx; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
-                if (stackNdx == topStackNdx) {
-                    // Top stack.
-                    showHomeBehindStack =
-                            stack.ensureActivitiesVisibleLocked(starting, configChanges);
-                } else {
-                    // Back stack.
-                    stack.ensureActivitiesVisibleLocked(starting, configChanges,
-                            showHomeBehindStack);
-                }
+                stack.ensureActivitiesVisibleLocked(starting, configChanges);
             }
         }
     }
@@ -2496,6 +2512,15 @@
         return homeInFront;
     }
 
+    /**
+     * Add background users to send boot completed events to.
+     * @param userId The user being started in the background
+     * @param uss The state object for the user.
+     */
+    public void startBackgroundUserLocked(int userId, UserStartedState uss) {
+        mStartingBackgroundUsers.add(uss);
+    }
+
     final ArrayList<ActivityRecord> processStoppingActivitiesLocked(boolean remove) {
         int N = mStoppingActivities.size();
         if (N <= 0) return null;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 9f0bc10..862932c 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -139,6 +139,9 @@
 
         userId = UserHandle.getUserId(info.applicationInfo.uid);
         creatorUid = info.applicationInfo.uid;
+        if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
+            intent.addFlags(Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+        }
     }
 
     void disposeThumbnail() {
@@ -246,6 +249,11 @@
         return mActivities.size() == 0;
     }
 
+    boolean autoRemoveFromRecents() {
+        return intent != null &&
+                (intent.getFlags() & Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS) != 0;
+    }
+
     /**
      * Completely remove all activities associated with an existing
      * task starting at a specified index.
diff --git a/services/core/java/com/android/server/am/UsageStatsService.java b/services/core/java/com/android/server/am/UsageStatsService.java
index 42cf900..4a5a554 100644
--- a/services/core/java/com/android/server/am/UsageStatsService.java
+++ b/services/core/java/com/android/server/am/UsageStatsService.java
@@ -17,26 +17,31 @@
 package com.android.server.am;
 
 import android.app.AppGlobals;
+import android.app.AppOpsManager;
+import android.app.UsageStats;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.content.res.Configuration;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.FileUtils;
 import android.os.Parcel;
+import android.os.ParcelableParcel;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.text.format.DateFormat;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.Slog;
+import android.util.TimeUtils;
 import android.util.Xml;
 
 import com.android.internal.app.IUsageStats;
 import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.PkgUsageStats;
 import com.android.internal.util.FastXmlSerializer;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -46,7 +51,6 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -55,8 +59,6 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 import java.util.TimeZone;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -75,7 +77,7 @@
     private static final String TAG = "UsageStats";
 
     // Current on-disk Parcel version
-    private static final int VERSION = 1008;
+    private static final int VERSION = 1010;
 
     private static final int CHECKIN_VERSION = 4;
 
@@ -94,13 +96,10 @@
 
     static IUsageStats sService;
     private Context mContext;
-    // structure used to maintain statistics since the last checkin.
-    final private ArrayMap<String, PkgUsageStatsExtended> mStats
-            = new ArrayMap<String, PkgUsageStatsExtended>();
+    private AppOpsManager mAppOps;
 
-    // Maintains the last time any component was resumed, for all time.
-    final private ArrayMap<String, ArrayMap<String, Long>> mLastResumeTimes
-            = new ArrayMap<String, ArrayMap<String, Long>>();
+    // structure used to maintain statistics since the last checkin.
+    private LocalUsageStats mStats = new LocalUsageStats();
 
     // To remove last-resume time stats when a pacakge is removed.
     private PackageMonitor mPackageMonitor;
@@ -115,6 +114,7 @@
     private String mLastResumedPkg;
     private String mLastResumedComp;
     private boolean mIsResumed;
+    private ConfigUsageStatsExtended mCurrentConfigStats;
     private File mFile;
     private AtomicFile mHistoryFile;
     private String mFileLeaf;
@@ -127,6 +127,30 @@
     private final AtomicLong mLastWriteElapsedTime = new AtomicLong(0);
     private final AtomicBoolean mUnforcedDiskWriteRunning = new AtomicBoolean(false);
 
+    static class LocalUsageStats extends UsageStats {
+        public LocalUsageStats() {
+        }
+        public LocalUsageStats(Parcel in, boolean extended) {
+            super(in, extended);
+        }
+        @Override
+        public PackageStats onNewPackageStats(String pkgName) {
+            return new PkgUsageStatsExtended(pkgName);
+        }
+        @Override
+        public PackageStats onNewPackageStats(Parcel in) {
+            return new PkgUsageStatsExtended(in);
+        }
+        @Override
+        public ConfigurationStats onNewConfigurationStats(Configuration config) {
+            return new ConfigUsageStatsExtended(config);
+        }
+        @Override
+        public ConfigurationStats onNewConfigurationStats(Parcel source) {
+            return new ConfigUsageStatsExtended(source);
+        }
+    }
+
     static class TimeStats {
         int mCount;
         final int[] mTimes = new int[NUM_LAUNCH_TIME_BINS];
@@ -166,27 +190,18 @@
         }
     }
 
-    static class PkgUsageStatsExtended {
+    static class PkgUsageStatsExtended extends UsageStats.PackageStats {
         final ArrayMap<String, TimeStats> mLaunchTimes
                 = new ArrayMap<String, TimeStats>();
         final ArrayMap<String, TimeStats> mFullyDrawnTimes
                 = new ArrayMap<String, TimeStats>();
-        int mLaunchCount;
-        long mUsageTime;
-        long mPausedTime;
-        long mResumedTime;
 
-        PkgUsageStatsExtended() {
-            mLaunchCount = 0;
-            mUsageTime = 0;
+        PkgUsageStatsExtended(String pkgName) {
+            super(pkgName);
         }
 
         PkgUsageStatsExtended(Parcel in) {
-            mLaunchCount = in.readInt();
-            mUsageTime = in.readLong();
-            if (localLOGV) Slog.v(TAG, "Launch count: " + mLaunchCount
-                    + ", Usage time:" + mUsageTime);
-
+            super(in);
             final int numLaunchTimeStats = in.readInt();
             if (localLOGV) Slog.v(TAG, "Reading launch times: " + numLaunchTimeStats);
             mLaunchTimes.ensureCapacity(numLaunchTimeStats);
@@ -208,18 +223,6 @@
             }
         }
 
-        void updateResume(String comp, boolean launched) {
-            if (launched) {
-                mLaunchCount++;
-            }
-            mResumedTime = SystemClock.elapsedRealtime();
-        }
-
-        void updatePause() {
-            mPausedTime =  SystemClock.elapsedRealtime();
-            mUsageTime += (mPausedTime - mResumedTime);
-        }
-
         void addLaunchCount(String comp) {
             TimeStats times = mLaunchTimes.get(comp);
             if (times == null) {
@@ -247,9 +250,7 @@
             times.add(millis);
         }
 
-        void writeToParcel(Parcel out) {
-            out.writeInt(mLaunchCount);
-            out.writeLong(mUsageTime);
+        public void writeExtendedToParcel(Parcel out, int parcelableFlags) {
             final int numLaunchTimeStats = mLaunchTimes.size();
             out.writeInt(numLaunchTimeStats);
             for (int i=0; i<numLaunchTimeStats; i++) {
@@ -264,11 +265,21 @@
             }
         }
 
-        void clear() {
+        @Override
+        public boolean clearUsageTimes() {
             mLaunchTimes.clear();
             mFullyDrawnTimes.clear();
-            mLaunchCount = 0;
-            mUsageTime = 0;
+            return super.clearUsageTimes();
+        }
+    }
+
+    static class ConfigUsageStatsExtended extends UsageStats.ConfigurationStats {
+        ConfigUsageStatsExtended(Configuration config) {
+            super(config);
+        }
+
+        ConfigUsageStatsExtended(Parcel in) {
+            super(in);
         }
     }
 
@@ -364,18 +375,9 @@
                    + VERSION + "; dropping");
             return;
         }
-        int N = in.readInt();
-        while (N > 0) {
-            N--;
-            String pkgName = in.readString();
-            if (pkgName == null) {
-                break;
-            }
-            if (localLOGV) Slog.v(TAG, "Reading package #" + N + ": " + pkgName);
-            PkgUsageStatsExtended pus = new PkgUsageStatsExtended(in);
-            synchronized (mStatsLock) {
-                mStats.put(pkgName, pus);
-            }
+        LocalUsageStats stats = new LocalUsageStats(in, true);
+        synchronized (mStatsLock) {
+            mStats = stats;
         }
     }
 
@@ -419,12 +421,9 @@
                                 try {
                                     long lastResumeTime = Long.parseLong(lastResumeTimeStr);
                                     synchronized (mStatsLock) {
-                                        ArrayMap<String, Long> lrt = mLastResumeTimes.get(pkg);
-                                        if (lrt == null) {
-                                            lrt = new ArrayMap<String, Long>();
-                                            mLastResumeTimes.put(pkg, lrt);
-                                        }
-                                        lrt.put(comp, lastResumeTime);
+                                        PkgUsageStatsExtended pus = (PkgUsageStatsExtended)
+                                                mStats.getOrCreatePackageStats(pkg);
+                                        pus.componentResumeTimes.put(comp, lastResumeTime);
                                     }
                                 } catch (NumberFormatException e) {
                                 }
@@ -543,6 +542,15 @@
             return;
         }
 
+        Parcel out = Parcel.obtain();
+        synchronized (mStatsLock) {
+            out.writeInt(VERSION);
+            mStats.writeExtendedToParcel(out, 0);
+            if (dayChanged) {
+                mStats.clearUsageTimes();
+            }
+        }
+
         synchronized (mFileLock) {
             // Get the most recent file
             mFileLeaf = getCurrentDateStr(FILE_PREFIX);
@@ -553,6 +561,7 @@
                 if (!backupFile.exists()) {
                     if (!mFile.renameTo(backupFile)) {
                         Slog.w(TAG, "Failed to persist new stats");
+                        out.recycle();
                         return;
                     }
                 } else {
@@ -562,14 +571,10 @@
 
             try {
                 // Write mStats to file
-                writeStatsFLOCK(mFile);
+                writeStatsFLOCK(mFile, out);
                 mLastWriteElapsedTime.set(currElapsedTime);
                 if (dayChanged) {
                     mLastWriteDay.set(curDay);
-                    // clear stats
-                    synchronized (mStats) {
-                        mStats.clear();
-                    }
                     mFile = new File(mDir, mFileLeaf);
                     checkFileLimitFLOCK();
                 }
@@ -590,17 +595,15 @@
                     backupFile.renameTo(mFile);
                 }
             }
+            out.recycle();
         }
         if (localLOGV) Slog.d(TAG, "Dumped usage stats.");
     }
 
-    private void writeStatsFLOCK(File file) throws IOException {
+    private void writeStatsFLOCK(File file, Parcel parcel) throws IOException {
         FileOutputStream stream = new FileOutputStream(file);
         try {
-            Parcel out = Parcel.obtain();
-            writeStatsToParcelFLOCK(out);
-            stream.write(out.marshall());
-            out.recycle();
+            stream.write(parcel.marshall());
             stream.flush();
         } finally {
             FileUtils.sync(stream);
@@ -608,29 +611,14 @@
         }
     }
 
-    private void writeStatsToParcelFLOCK(Parcel out) {
-        synchronized (mStatsLock) {
-            out.writeInt(VERSION);
-            Set<String> keys = mStats.keySet();
-            out.writeInt(keys.size());
-            for (String key : keys) {
-                PkgUsageStatsExtended pus = mStats.get(key);
-                out.writeString(key);
-                pus.writeToParcel(out);
-            }
-        }
-    }
-
     /** Filter out stats for any packages which aren't present anymore. */
     private void filterHistoryStats() {
         synchronized (mStatsLock) {
             IPackageManager pm = AppGlobals.getPackageManager();
-            for (int i=0; i<mLastResumeTimes.size(); i++) {
-                String pkg = mLastResumeTimes.keyAt(i);
+            for (int i=mStats.mPackages.size()-1; i>=0; i--) {
                 try {
-                    if (pm.getPackageUid(pkg, 0) < 0) {
-                        mLastResumeTimes.removeAt(i);
-                        i--;
+                    if (pm.getPackageUid(mStats.mPackages.valueAt(i).getPackageName(), 0) < 0) {
+                        mStats.mPackages.removeAt(i);
                     }
                 } catch (RemoteException e) {
                 }
@@ -648,10 +636,12 @@
             out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
             out.startTag(null, "usage-history");
             synchronized (mStatsLock) {
-                for (int i=0; i<mLastResumeTimes.size(); i++) {
+                int NP = mStats.mPackages.size();
+                for (int i=0; i<NP; i++) {
+                    UsageStats.PackageStats ps = mStats.mPackages.valueAt(i);
                     out.startTag(null, "pkg");
-                    out.attribute(null, "name", mLastResumeTimes.keyAt(i));
-                    ArrayMap<String, Long> comp = mLastResumeTimes.valueAt(i);
+                    out.attribute(null, "name", ps.getPackageName());
+                    ArrayMap<String, Long> comp = ps.componentResumeTimes;
                     for (int j=0; j<comp.size(); j++) {
                         out.startTag(null, "comp");
                         out.attribute(null, "name", comp.keyAt(j));
@@ -678,6 +668,10 @@
         ServiceManager.addService(SERVICE_NAME, asBinder());
     }
 
+    public void systemReady() {
+        mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
+    }
+
     /**
      * Start watching packages to remove stats when a package is uninstalled.
      * May only be called when the package manager is ready.
@@ -687,7 +681,7 @@
             @Override
             public void onPackageRemovedAllUsers(String packageName, int uid) {
                 synchronized (mStatsLock) {
-                    mLastResumeTimes.remove(packageName);
+                    mStats.mPackages.remove(packageName);
                 }
             }
         };
@@ -729,9 +723,10 @@
                     // to recover.
                     if (REPORT_UNEXPECTED) Slog.i(TAG, "Unexpected resume of " + pkgName
                             + " while already resumed in " + mLastResumedPkg);
-                    PkgUsageStatsExtended pus = mStats.get(mLastResumedPkg);
+                    PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(
+                            mLastResumedPkg);
                     if (pus != null) {
-                        pus.updatePause();
+                        pus.pause();
                     }
                 }
             }
@@ -744,22 +739,13 @@
             mLastResumedComp = componentName.getClassName();
 
             if (localLOGV) Slog.i(TAG, "started component:" + pkgName);
-            PkgUsageStatsExtended pus = mStats.get(pkgName);
-            if (pus == null) {
-                pus = new PkgUsageStatsExtended();
-                mStats.put(pkgName, pus);
-            }
-            pus.updateResume(mLastResumedComp, !samePackage);
+            PkgUsageStatsExtended pus = (PkgUsageStatsExtended)
+                    mStats.getOrCreatePackageStats(pkgName);
+            pus.resume(!samePackage);
             if (!sameComp) {
                 pus.addLaunchCount(mLastResumedComp);
             }
-
-            ArrayMap<String, Long> componentResumeTimes = mLastResumeTimes.get(pkgName);
-            if (componentResumeTimes == null) {
-                componentResumeTimes = new ArrayMap<String, Long>();
-                mLastResumeTimes.put(pkgName, componentResumeTimes);
-            }
-            componentResumeTimes.put(mLastResumedComp, System.currentTimeMillis());
+            pus.componentResumeTimes.put(mLastResumedComp, System.currentTimeMillis());
         }
     }
 
@@ -782,13 +768,13 @@
 
             if (localLOGV) Slog.i(TAG, "paused component:"+pkgName);
 
-            PkgUsageStatsExtended pus = mStats.get(pkgName);
+            PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
             if (pus == null) {
                 // Weird some error here
                 Slog.i(TAG, "No package stats for pkg:"+pkgName);
                 return;
             }
-            pus.updatePause();
+            pus.pause();
         }
 
         // Persist current data to file if needed.
@@ -808,7 +794,7 @@
         writeStatsToFile(false, false);
 
         synchronized (mStatsLock) {
-            PkgUsageStatsExtended pus = mStats.get(pkgName);
+            PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
             if (pus != null) {
                 pus.addLaunchTime(componentName.getClassName(), millis);
             }
@@ -827,13 +813,29 @@
         writeStatsToFile(false, false);
 
         synchronized (mStatsLock) {
-            PkgUsageStatsExtended pus = mStats.get(pkgName);
+            PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
             if (pus != null) {
                 pus.addFullyDrawnTime(componentName.getClassName(), millis);
             }
         }
     }
 
+    public void noteStartConfig(Configuration config) {
+        enforceCallingPermission();
+        synchronized (mStatsLock) {
+            config = new Configuration(config);
+            ConfigUsageStatsExtended cus = (ConfigUsageStatsExtended)
+                    mStats.getOrCreateConfigurationStats(config);
+            if (cus != mCurrentConfigStats) {
+                if (mCurrentConfigStats != null) {
+                    mCurrentConfigStats.stop();
+                }
+                cus.start();
+                mCurrentConfigStats = cus;
+            }
+        }
+    }
+
     public void enforceCallingPermission() {
         if (Binder.getCallingPid() == Process.myPid()) {
             return;
@@ -843,53 +845,71 @@
     }
 
     @Override
-    public PkgUsageStats getPkgUsageStats(ComponentName componentName) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+    public UsageStats.PackageStats getPkgUsageStats(String callingPkg,
+            ComponentName componentName) {
+        checkCallerPermission(callingPkg, "getPkgUsageStats");
         String pkgName;
         if ((componentName == null) ||
                 ((pkgName = componentName.getPackageName()) == null)) {
             return null;
         }
         synchronized (mStatsLock) {
-            PkgUsageStatsExtended pus = mStats.get(pkgName);
-            Map<String, Long> lastResumeTimes = mLastResumeTimes.get(pkgName);
-            if (pus == null && lastResumeTimes == null) {
+            PkgUsageStatsExtended pus = (PkgUsageStatsExtended)mStats.getPackageStats(pkgName);
+            if (pus == null) {
                 return null;
             }
-            int launchCount = pus != null ? pus.mLaunchCount : 0;
-            long usageTime = pus != null ? pus.mUsageTime : 0;
-            return new PkgUsageStats(pkgName, launchCount, usageTime, lastResumeTimes);
+            return new UsageStats.PackageStats(pus);
         }
     }
 
     @Override
-    public PkgUsageStats[] getAllPkgUsageStats() {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.PACKAGE_USAGE_STATS, null);
+    public UsageStats.PackageStats[] getAllPkgUsageStats(String callingPkg) {
+        checkCallerPermission(callingPkg, "getAllPkgUsageStats");
         synchronized (mStatsLock) {
-            int size = mLastResumeTimes.size();
-            if (size <= 0) {
+            int NP = mStats.mPackages.size();
+            if (NP <= 0) {
                 return null;
             }
-            PkgUsageStats retArr[] = new PkgUsageStats[size];
-            for (int i=0; i<size; i++) {
-                String pkg = mLastResumeTimes.keyAt(i);
-                long usageTime = 0;
-                int launchCount = 0;
-
-                PkgUsageStatsExtended pus = mStats.get(pkg);
-                if (pus != null) {
-                    usageTime = pus.mUsageTime;
-                    launchCount = pus.mLaunchCount;
-                }
-                retArr[i] = new PkgUsageStats(pkg, launchCount, usageTime,
-                        mLastResumeTimes.valueAt(i));
+            UsageStats.PackageStats retArr[] = new UsageStats.PackageStats[NP];
+            for (int p=0; p<NP; p++) {
+                UsageStats.PackageStats ps = mStats.mPackages.valueAt(p);
+                retArr[p] = new UsageStats.PackageStats(ps);
             }
             return retArr;
         }
     }
 
+    @Override
+    public ParcelableParcel getCurrentStats(String callingPkg) {
+        checkCallerPermission(callingPkg, "getCurrentStats");
+        synchronized (mStatsLock) {
+            ParcelableParcel out = new ParcelableParcel(null);
+            mStats.writeToParcel(out.getParcel(), 0);
+            return out;
+        }
+    }
+
+    private void checkCallerPermission(String callingPkg, String callingOp) {
+        // Because the permission for this is system-only, its use with
+        // app ops is a little different: the op is disabled by default,
+        // and enabling it allows apps to get access even if they don't
+        // hold the permission.
+        int mode = mAppOps.noteOpNoThrow(AppOpsManager.OP_GET_USAGE_STATS, Binder.getCallingUid(),
+                callingPkg);
+        if (mode == AppOpsManager.MODE_ALLOWED) {
+            return;
+        } else if (mode != AppOpsManager.MODE_IGNORED) {
+            if (mContext.checkCallingOrSelfPermission(
+                    android.Manifest.permission.PACKAGE_USAGE_STATS)
+                    == PackageManager.PERMISSION_GRANTED) {
+                return;
+            }
+        }
+
+        String msg = "Package " + callingPkg + " not allowed to call " + callingOp;
+        throw new SecurityException(msg);
+    }
+
     static byte[] readFully(FileInputStream stream) throws IOException {
         int pos = 0;
         int avail = stream.available();
@@ -963,31 +983,28 @@
             return;
         }
 
-        pw.println(sb.toString());
-        int N = in.readInt();
+        final LocalUsageStats stats = new LocalUsageStats(in, true);
+        final long time = SystemClock.elapsedRealtime();
 
-        while (N > 0) {
-            N--;
-            String pkgName = in.readString();
-            if (pkgName == null) {
-                break;
-            }
+        pw.println(sb.toString());
+        int NP = stats.mPackages.size();
+        for (int p=0; p<NP; p++) {
+            PkgUsageStatsExtended pus = (PkgUsageStatsExtended)stats.mPackages.valueAt(p);
             sb.setLength(0);
-            PkgUsageStatsExtended pus = new PkgUsageStatsExtended(in);
-            if (packages != null && !packages.contains(pkgName)) {
+            if (packages != null && !packages.contains(pus.getPackageName())) {
                 // This package has not been requested -- don't print
                 // anything for it.
             } else if (isCompactOutput) {
                 sb.append("P:");
-                sb.append(pkgName);
+                sb.append(pus.getPackageName());
                 sb.append(',');
-                sb.append(pus.mLaunchCount);
+                sb.append(pus.getLaunchCount());
                 sb.append(',');
-                sb.append(pus.mUsageTime);
+                sb.append(pus.getUsageTime(time));
                 sb.append('\n');
                 final int NLT = pus.mLaunchTimes.size();
                 for (int i=0; i<NLT; i++) {
-                    sb.append("A:");
+                    sb.append("L:");
                     String activity = pus.mLaunchTimes.keyAt(i);
                     sb.append(activity);
                     TimeStats times = pus.mLaunchTimes.valueAt(i);
@@ -1001,7 +1018,7 @@
                 }
                 final int NFDT = pus.mFullyDrawnTimes.size();
                 for (int i=0; i<NFDT; i++) {
-                    sb.append("A:");
+                    sb.append("D:");
                     String activity = pus.mFullyDrawnTimes.keyAt(i);
                     sb.append(activity);
                     TimeStats times = pus.mFullyDrawnTimes.valueAt(i);
@@ -1011,15 +1028,23 @@
                     }
                     sb.append('\n');
                 }
+                final int NC = pus.componentResumeTimes.size();
+                for (int c=0; c<NC; c++) {
+                    pw.print("R:"); pw.print(pus.componentResumeTimes.keyAt(c)); pw.print(",");
+                    pw.println(pus.componentResumeTimes.valueAt(c));
+                }
 
             } else {
                 sb.append("  ");
-                sb.append(pkgName);
-                sb.append(": ");
-                sb.append(pus.mLaunchCount);
-                sb.append(" times, ");
-                sb.append(pus.mUsageTime);
-                sb.append(" ms");
+                sb.append(pus.getPackageName());
+                if (pus.getLaunchCount() != 0 || pus.getUsageTime(time) != 0) {
+                    sb.append(": ");
+                    sb.append(pus.getLaunchCount());
+                    sb.append(" times, ");
+                    TimeUtils.formatDuration(pus.getUsageTime(time), sb);
+                } else {
+                    sb.append(":");
+                }
                 sb.append('\n');
                 final int NLT = pus.mLaunchTimes.size();
                 for (int i=0; i<NLT; i++) {
@@ -1084,10 +1109,50 @@
                     }
                     sb.append('\n');
                 }
+                final int NC = pus.componentResumeTimes.size();
+                for (int c=0; c<NC; c++) {
+                    sb.append("    ");
+                    sb.append(pus.componentResumeTimes.keyAt(c));
+                    sb.append(" last resumed ");
+                    sb.append(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+                            pus.componentResumeTimes.valueAt(c)).toString());
+                    sb.append('\n');
+                }
             }
 
             pw.write(sb.toString());
         }
+        if (packages == null) {
+            int NC = stats.mConfigurations.size();
+            for (int c=0; c<NC; c++) {
+                ConfigUsageStatsExtended cus
+                        = (ConfigUsageStatsExtended)stats.mConfigurations.valueAt(c);
+                sb.setLength(0);
+                if (isCompactOutput) {
+                    sb.append("C:"); sb.append(cus.getConfiguration().toString());
+                    sb.append(","); sb.append(cus.getUsageCount()); sb.append(",");
+                    sb.append(cus.getUsageTime(time));
+                } else {
+                    sb.append("  ");
+                    sb.append(cus.getConfiguration().toString());
+                    sb.append(":\n");
+                    if (cus.getUsageCount() != 0 || cus.getUsageTime(time) != 0) {
+                        sb.append("    Used ");
+                        sb.append(cus.getUsageCount());
+                        sb.append(" times, ");
+                        TimeUtils.formatDuration(cus.getUsageTime(time), sb);
+                        sb.append("\n");
+                    }
+                    if (cus.getLastUsedTime() > 0) {
+                        sb.append("    Last used: ");
+                        sb.append(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
+                                cus.getLastUsedTime()).toString());
+                        sb.append("\n");
+                    }
+                }
+                pw.write(sb.toString());
+            }
+        }
     }
 
     /**
@@ -1174,5 +1239,4 @@
             collectDumpInfoFLOCK(pw, isCompactOutput, deleteAfterPrint, packages);
         }
     }
-
 }
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 8815d0f..0749f24 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -24,7 +24,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -157,14 +157,14 @@
      * @param proxy Proxy information that is about to be broadcast.
      * @return Returns true when the broadcast should not be sent
      */
-    public synchronized boolean setCurrentProxyScriptUrl(ProxyProperties proxy) {
-        if (!TextUtils.isEmpty(proxy.getPacFileUrl())) {
+    public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
+        if (proxy.getPacFileUrl() != null) {
             if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
                 // Allow to send broadcast, nothing to do.
                 return false;
             }
             synchronized (mProxyLock) {
-                mPacUrl = proxy.getPacFileUrl();
+                mPacUrl = proxy.getPacFileUrl().toString();
             }
             mCurrentDelay = DELAY_1;
             mHasSentBroadcast = false;
@@ -268,7 +268,7 @@
         // Already bound no need to bind again.
         if ((mProxyConnection != null) && (mConnection != null)) {
             if (mLastPort != -1) {
-                sendPacBroadcast(new ProxyProperties(mPacUrl, mLastPort));
+                sendPacBroadcast(new ProxyInfo(mPacUrl, mLastPort));
             } else {
                 Log.e(TAG, "Received invalid port from Local Proxy,"
                         + " PAC will not be operational");
@@ -362,7 +362,7 @@
         mLastPort = -1;
     }
 
-    private void sendPacBroadcast(ProxyProperties proxy) {
+    private void sendPacBroadcast(ProxyInfo proxy) {
         mConnectivityHandler.sendMessage(mConnectivityHandler.obtainMessage(mProxyMessage, proxy));
     }
 
@@ -371,7 +371,7 @@
             return;
         }
         if (!mHasSentBroadcast) {
-            sendPacBroadcast(new ProxyProperties(mPacUrl, mLastPort));
+            sendPacBroadcast(new ProxyInfo(mPacUrl, mLastPort));
             mHasSentBroadcast = true;
         }
     }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 3ae0fd5..3d5fb57 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -518,6 +518,11 @@
                 // Brighten quickly.
                 slow = false;
             }
+            // If low power mode is enabled, brightness level
+            // would be scaled down to half
+            if (mPowerRequest.lowPowerMode) {
+                target = target/2;
+            }
             animateScreenBrightness(clampScreenBrightness(target),
                     slow ? BRIGHTNESS_RAMP_RATE_SLOW : BRIGHTNESS_RAMP_RATE_FAST);
         } else {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 54cb035..0f5805c 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -323,6 +323,10 @@
 
         mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
         mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
+
+        if (mWiredAccessoryCallbacks != null) {
+            mWiredAccessoryCallbacks.systemReady();
+        }
     }
 
     private void reloadKeyboardLayouts() {
@@ -1588,6 +1592,7 @@
      */
     public interface WiredAccessoryCallbacks {
         public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask);
+        public void systemReady();
     }
 
     /**
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7aa5d79..4698587 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -198,8 +198,7 @@
     private final UserProfiles mUserProfiles = new UserProfiles();
     private NotificationListeners mListeners;
     private ConditionProviders mConditionProviders;
-
-    private final NotificationUsageStats mUsageStats = new NotificationUsageStats();
+    private NotificationUsageStats mUsageStats;
 
     private static final String EXTRA_INTERCEPT = "android.intercept";
 
@@ -445,7 +444,7 @@
     public static final class NotificationRecord
     {
         final StatusBarNotification sbn;
-        final SingleNotificationStats stats = new SingleNotificationStats();
+        SingleNotificationStats stats;
         IBinder statusBarKey;
 
         NotificationRecord(StatusBarNotification sbn)
@@ -472,6 +471,7 @@
             pw.println(prefix + String.format("  defaults=0x%08x flags=0x%08x",
                     notification.defaults, notification.flags));
             pw.println(prefix + "  sound=" + notification.sound);
+            pw.println(prefix + String.format("  color=0x%08x", notification.color));
             pw.println(prefix + "  vibrate=" + Arrays.toString(notification.vibrate));
             pw.println(prefix + String.format("  led=0x%08x onMs=%d offMs=%d",
                     notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
@@ -858,6 +858,7 @@
         });
         final File systemDir = new File(Environment.getDataDirectory(), "system");
         mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
+        mUsageStats = new NotificationUsageStats(getContext());
 
         importOldBlockDb();
 
@@ -1638,7 +1639,7 @@
                     } else {
                         old = mNotificationList.get(index);
                         mNotificationList.set(index, r);
-                        mUsageStats.registerUpdatedByApp(r);
+                        mUsageStats.registerUpdatedByApp(r, old);
                         // Make sure we don't lose the foreground service state.
                         if (old != null) {
                             notification.flags |=
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index d9e2b91..a60e95b 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -18,8 +18,17 @@
 
 import com.android.server.notification.NotificationManagerService.NotificationRecord;
 
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
 import android.os.SystemClock;
 import android.service.notification.StatusBarNotification;
+import android.util.Log;
 
 import java.io.PrintWriter;
 import java.util.HashMap;
@@ -37,24 +46,31 @@
  * {@hide}
  */
 public class NotificationUsageStats {
-
     // Guarded by synchronized(this).
     private final Map<String, AggregatedStats> mStats = new HashMap<String, AggregatedStats>();
+    private final SQLiteLog mSQLiteLog;
+
+    public NotificationUsageStats(Context context) {
+        mSQLiteLog = new SQLiteLog(context);
+    }
 
     /**
      * Called when a notification has been posted.
      */
     public synchronized void registerPostedByApp(NotificationRecord notification) {
+        notification.stats = new SingleNotificationStats();
         notification.stats.posttimeElapsedMs = SystemClock.elapsedRealtime();
         for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
             stats.numPostedByApp++;
         }
+        mSQLiteLog.logPosted(notification);
     }
 
     /**
      * Called when a notification has been updated.
      */
-    public void registerUpdatedByApp(NotificationRecord notification) {
+    public void registerUpdatedByApp(NotificationRecord notification, NotificationRecord old) {
+        notification.stats = old.stats;
         for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
             stats.numUpdatedByApp++;
         }
@@ -68,6 +84,7 @@
             stats.numRemovedByApp++;
             stats.collect(notification.stats);
         }
+        mSQLiteLog.logRemoved(notification);
     }
 
     /**
@@ -79,6 +96,7 @@
             stats.numDismissedByUser++;
             stats.collect(notification.stats);
         }
+        mSQLiteLog.logDismissed(notification);
     }
 
     /**
@@ -89,6 +107,7 @@
         for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
             stats.numClickedByUser++;
         }
+        mSQLiteLog.logClicked(notification);
     }
 
     /**
@@ -146,6 +165,7 @@
         for (AggregatedStats as : mStats.values()) {
             as.dump(pw, indent);
         }
+        mSQLiteLog.dump(pw, indent);
     }
 
     /**
@@ -274,4 +294,211 @@
                     '}';
         }
     }
+
+    private static class SQLiteLog {
+        private static final String TAG = "NotificationSQLiteLog";
+
+        // Message types passed to the background handler.
+        private static final int MSG_POST = 1;
+        private static final int MSG_CLICK = 2;
+        private static final int MSG_REMOVE = 3;
+        private static final int MSG_DISMISS = 4;
+
+        private static final String DB_NAME = "notification_log.db";
+        private static final int DB_VERSION = 1;
+
+        /** Age in ms after which events are pruned from the DB. */
+        private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L;  // 1 week
+        /** Delay between pruning the DB. Used to throttle pruning. */
+        private static final long PRUNE_MIN_DELAY_MS = 6 * 60 * 60 * 1000L;  // 6 hours
+        /** Mininum number of writes between pruning the DB. Used to throttle pruning. */
+        private static final long PRUNE_MIN_WRITES = 1024;
+
+        // Table 'log'
+        private static final String TAB_LOG = "log";
+        private static final String COL_EVENT_USER_ID = "event_user_id";
+        private static final String COL_EVENT_TYPE = "event_type";
+        private static final String COL_EVENT_TIME = "event_time_ms";
+        private static final String COL_KEY = "key";
+        private static final String COL_PKG = "pkg";
+        private static final String COL_NOTIFICATION_ID = "nid";
+        private static final String COL_TAG = "tag";
+        private static final String COL_WHEN_MS = "when_ms";
+        private static final String COL_DEFAULTS = "defaults";
+        private static final String COL_FLAGS = "flags";
+        private static final String COL_PRIORITY = "priority";
+        private static final String COL_CATEGORY = "category";
+        private static final String COL_ACTION_COUNT = "action_count";
+
+        private static final int EVENT_TYPE_POST = 1;
+        private static final int EVENT_TYPE_CLICK = 2;
+        private static final int EVENT_TYPE_REMOVE = 3;
+        private static final int EVENT_TYPE_DISMISS = 4;
+
+        private static long sLastPruneMs;
+        private static long sNumWrites;
+
+        private final SQLiteOpenHelper mHelper;
+        private final Handler mWriteHandler;
+
+        private static final long DAY_MS = 24 * 60 * 60 * 1000;
+
+        public SQLiteLog(Context context) {
+            HandlerThread backgroundThread = new HandlerThread("notification-sqlite-log",
+                    android.os.Process.THREAD_PRIORITY_BACKGROUND);
+            backgroundThread.start();
+            mWriteHandler = new Handler(backgroundThread.getLooper()) {
+                @Override
+                public void handleMessage(Message msg) {
+                    NotificationRecord r = (NotificationRecord) msg.obj;
+                    long nowMs = System.currentTimeMillis();
+                    switch (msg.what) {
+                        case MSG_POST:
+                            writeEvent(r.sbn.getPostTime(), EVENT_TYPE_POST, r, true);
+                            break;
+                        case MSG_CLICK:
+                            writeEvent(nowMs, EVENT_TYPE_CLICK, r, false);
+                            break;
+                        case MSG_REMOVE:
+                            writeEvent(nowMs, EVENT_TYPE_REMOVE, r, false);
+                            break;
+                        case MSG_DISMISS:
+                            writeEvent(nowMs, EVENT_TYPE_DISMISS, r, false);
+                            break;
+                        default:
+                            Log.wtf(TAG, "Unknown message type: " + msg.what);
+                            break;
+                    }
+                }
+            };
+            mHelper = new SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
+                @Override
+                public void onCreate(SQLiteDatabase db) {
+                    db.execSQL("CREATE TABLE " + TAB_LOG + " (" +
+                            "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
+                            COL_EVENT_USER_ID + " INT," +
+                            COL_EVENT_TYPE + " INT," +
+                            COL_EVENT_TIME + " INT," +
+                            COL_KEY + " TEXT," +
+                            COL_PKG + " TEXT," +
+                            COL_NOTIFICATION_ID + " INT," +
+                            COL_TAG + " TEXT," +
+                            COL_WHEN_MS + " INT," +
+                            COL_DEFAULTS + " INT," +
+                            COL_FLAGS + " INT," +
+                            COL_PRIORITY + " INT," +
+                            COL_CATEGORY + " TEXT," +
+                            COL_ACTION_COUNT + " INT" +
+                            ")");
+                }
+
+                @Override
+                public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+                    db.execSQL("DROP TABLE IF EXISTS " + TAB_LOG);
+                    onCreate(db);
+                }
+            };
+        }
+
+        public void logPosted(NotificationRecord notification) {
+            mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_POST, notification));
+        }
+
+        public void logClicked(NotificationRecord notification) {
+            mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_CLICK, notification));
+        }
+
+        public void logRemoved(NotificationRecord notification) {
+            mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_REMOVE, notification));
+        }
+
+        public void logDismissed(NotificationRecord notification) {
+            mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_DISMISS, notification));
+        }
+
+        public void printPostFrequencies(PrintWriter pw, String indent) {
+            SQLiteDatabase db = mHelper.getReadableDatabase();
+            long nowMs = System.currentTimeMillis();
+            String q = "SELECT " +
+                    COL_EVENT_USER_ID + ", " +
+                    COL_PKG + ", " +
+                    // Bucket by day by looking at 'floor((nowMs - eventTimeMs) / dayMs)'
+                    "CAST(((" + nowMs + " - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " +
+                        "AS day, " +
+                    "COUNT(*) AS cnt " +
+                    "FROM " + TAB_LOG + " " +
+                    "WHERE " +
+                    COL_EVENT_TYPE + "=" + EVENT_TYPE_POST + " " +
+                    "GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
+            Cursor cursor = db.rawQuery(q, null);
+            try {
+                for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
+                    int userId = cursor.getInt(0);
+                    String pkg = cursor.getString(1);
+                    int day = cursor.getInt(2);
+                    int count = cursor.getInt(3);
+                    pw.println(indent + "post_frequency{user_id=" + userId + ",pkg=" + pkg +
+                            ",day=" + day + ",count=" + count + "}");
+                }
+            } finally {
+                cursor.close();
+            }
+        }
+
+        private void writeEvent(long eventTimeMs, int eventType, NotificationRecord r,
+                boolean populateNotificationDetails) {
+            ContentValues cv = new ContentValues();
+            cv.put(COL_EVENT_USER_ID, r.sbn.getUser().getIdentifier());
+            cv.put(COL_EVENT_TIME, eventTimeMs);
+            cv.put(COL_EVENT_TYPE, eventType);
+            putNotificationIdentifiers(r, cv);
+            if (populateNotificationDetails) {
+                putNotificationDetails(r, cv);
+            }
+            SQLiteDatabase db = mHelper.getWritableDatabase();
+            if (db.insert(TAB_LOG, null, cv) < 0) {
+                Log.wtf(TAG, "Error while trying to insert values: " + cv);
+            }
+            sNumWrites++;
+            pruneIfNecessary(db);
+        }
+
+        private void pruneIfNecessary(SQLiteDatabase db) {
+            // Prune if we haven't in a while.
+            long nowMs = System.currentTimeMillis();
+            if (sNumWrites > PRUNE_MIN_WRITES ||
+                    nowMs - sLastPruneMs > PRUNE_MIN_DELAY_MS) {
+                sNumWrites = 0;
+                sLastPruneMs = nowMs;
+                long horizonStartMs = nowMs - HORIZON_MS;
+                int deletedRows = db.delete(TAB_LOG, COL_EVENT_TIME + " < ?",
+                        new String[] { String.valueOf(horizonStartMs) });
+                Log.d(TAG, "Pruned event entries: " + deletedRows);
+            }
+        }
+
+        private static void putNotificationIdentifiers(NotificationRecord r, ContentValues outCv) {
+            outCv.put(COL_KEY, r.sbn.getKey());
+            outCv.put(COL_PKG, r.sbn.getPackageName());
+        }
+
+        private static void putNotificationDetails(NotificationRecord r, ContentValues outCv) {
+            outCv.put(COL_NOTIFICATION_ID, r.sbn.getId());
+            if (r.sbn.getTag() != null) {
+                outCv.put(COL_TAG, r.sbn.getTag());
+            }
+            outCv.put(COL_WHEN_MS, r.sbn.getPostTime());
+            outCv.put(COL_FLAGS, r.getNotification().flags);
+            outCv.put(COL_PRIORITY, r.getNotification().priority);
+            if (r.getNotification().category != null) {
+                outCv.put(COL_CATEGORY, r.getNotification().category);
+            }
+            outCv.put(COL_ACTION_COUNT, r.getNotification().actions != null ?
+                    r.getNotification().actions.length : 0);
+        }
+
+        public void dump(PrintWriter pw, String indent) {
+            printPostFrequencies(pw, indent);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
new file mode 100644
index 0000000..f2db791
--- /dev/null
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.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 com.android.server.pm;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Log;
+
+import java.util.HashSet;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * {@hide}
+ */
+public class BackgroundDexOptService {
+
+    static final String TAG = "BackgroundDexOptService";
+
+    private final BroadcastReceiver mIdleMaintenanceReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)) {
+                onIdleStart();
+            } else if (Intent.ACTION_IDLE_MAINTENANCE_END.equals(action)) {
+                onIdleStop();
+            }
+        }
+    };
+
+    final PackageManagerService mPackageManager;
+
+    final AtomicBoolean mIdleTime = new AtomicBoolean(false);
+
+    public BackgroundDexOptService(Context context) {
+        mPackageManager = (PackageManagerService)ServiceManager.getService("package");
+
+        IntentFilter idleMaintenanceFilter = new IntentFilter();
+        idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START);
+        idleMaintenanceFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_END);
+        context.registerReceiverAsUser(mIdleMaintenanceReceiver, UserHandle.ALL,
+                                       idleMaintenanceFilter, null, null);
+    }
+
+    public boolean onIdleStart() {
+        Log.i(TAG, "onIdleStart");
+        if (mPackageManager.isStorageLow()) {
+            return false;
+        }
+        final HashSet<String> pkgs = mPackageManager.getPackagesThatNeedDexOpt();
+        if (pkgs == null) {
+            return false;
+        }
+        mIdleTime.set(true);
+        new Thread("BackgroundDexOptService_DexOpter") {
+            @Override
+            public void run() {
+                for (String pkg : pkgs) {
+                    if (!mIdleTime.get()) {
+                        break;
+                    }
+                    mPackageManager.performDexOpt(pkg, false);
+                }
+            }
+        }.start();
+        return true;
+    }
+
+    public void onIdleStop() {
+        Log.i(TAG, "onIdleStop");
+        mIdleTime.set(false);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 48e9737..bd28e04 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -239,8 +239,10 @@
 
     private class MyPackageMonitor extends PackageMonitor {
 
-        /** Checks if user is a profile of or same as listeningUser. */
-        private boolean isProfileOf(UserHandle user, UserHandle listeningUser, String debugMsg) {
+        /** Checks if user is a profile of or same as listeningUser.
+          * and the user is enabled. */
+        private boolean isEnabledProfileOf(UserHandle user, UserHandle listeningUser,
+                String debugMsg) {
             if (user.getIdentifier() == listeningUser.getIdentifier()) {
                 if (DEBUG) Log.d(TAG, "Delivering msg to same user " + debugMsg);
                 return true;
@@ -251,7 +253,8 @@
                 UserInfo listeningUserInfo = mUm.getUserInfo(listeningUser.getIdentifier());
                 if (userInfo == null || listeningUserInfo == null
                         || userInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID
-                        || userInfo.profileGroupId != listeningUserInfo.profileGroupId) {
+                        || userInfo.profileGroupId != listeningUserInfo.profileGroupId
+                        || !userInfo.isEnabled()) {
                     if (DEBUG) {
                         Log.d(TAG, "Not delivering msg from " + user + " to " + listeningUser + ":"
                                 + debugMsg);
@@ -276,7 +279,7 @@
             for (int i = 0; i < n; i++) {
                 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
-                if (!isProfileOf(user, listeningUser, "onPackageAdded")) continue;
+                if (!isEnabledProfileOf(user, listeningUser, "onPackageAdded")) continue;
                 try {
                     listener.onPackageAdded(user, packageName);
                 } catch (RemoteException re) {
@@ -295,7 +298,7 @@
             for (int i = 0; i < n; i++) {
                 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
-                if (!isProfileOf(user, listeningUser, "onPackageRemoved")) continue;
+                if (!isEnabledProfileOf(user, listeningUser, "onPackageRemoved")) continue;
                 try {
                     listener.onPackageRemoved(user, packageName);
                 } catch (RemoteException re) {
@@ -314,7 +317,7 @@
             for (int i = 0; i < n; i++) {
                 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
-                if (!isProfileOf(user, listeningUser, "onPackageModified")) continue;
+                if (!isEnabledProfileOf(user, listeningUser, "onPackageModified")) continue;
                 try {
                     listener.onPackageChanged(user, packageName);
                 } catch (RemoteException re) {
@@ -333,7 +336,7 @@
             for (int i = 0; i < n; i++) {
                 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
-                if (!isProfileOf(user, listeningUser, "onPackagesAvailable")) continue;
+                if (!isEnabledProfileOf(user, listeningUser, "onPackagesAvailable")) continue;
                 try {
                     listener.onPackagesAvailable(user, packages, isReplacing());
                 } catch (RemoteException re) {
@@ -352,7 +355,7 @@
             for (int i = 0; i < n; i++) {
                 IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
                 UserHandle listeningUser = (UserHandle) mListeners.getBroadcastCookie(i);
-                if (!isProfileOf(user, listeningUser, "onPackagesUnavailable")) continue;
+                if (!isEnabledProfileOf(user, listeningUser, "onPackagesUnavailable")) continue;
                 try {
                     listener.onPackagesUnavailable(user, packages, isReplacing());
                 } catch (RemoteException re) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 72fc295..a7f4b28 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -23,17 +23,19 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.system.OsConstants.S_IRWXU;
+import static android.os.Process.PACKAGE_INFO_GID;
+import static android.os.Process.SYSTEM_UID;
 import static android.system.OsConstants.S_IRGRP;
-import static android.system.OsConstants.S_IXGRP;
 import static android.system.OsConstants.S_IROTH;
+import static android.system.OsConstants.S_IRWXU;
+import static android.system.OsConstants.S_IXGRP;
 import static android.system.OsConstants.S_IXOTH;
-import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER;
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
+import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_USER_OWNER;
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.ArrayUtils.removeInt;
 
-import android.content.pm.PackageParser.*;
+import com.android.internal.R;
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.NativeLibraryHelper;
@@ -43,10 +45,13 @@
 import com.android.internal.util.XmlUtils;
 import com.android.server.EventLogTags;
 import com.android.server.IntentResolver;
-import com.android.server.ServiceThread;
-
 import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
 import com.android.server.Watchdog;
+import com.android.server.pm.Settings.DatabaseVersion;
+import com.android.server.storage.DeviceStorageMonitorInternal;
+import com.android.server.storage.DeviceStorageMonitorInternal;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -82,6 +87,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageParser.ActivityIntentInfo;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageStats;
 import android.content.pm.PackageUserState;
@@ -125,6 +131,7 @@
 import android.system.Os;
 import android.system.StructStat;
 import android.text.TextUtils;
+import android.util.AtomicFile;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
@@ -135,6 +142,7 @@
 import android.util.Xml;
 import android.view.Display;
 
+import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
@@ -144,7 +152,9 @@
 import java.io.FileReader;
 import java.io.FilenameFilter;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
 import java.security.NoSuchAlgorithmException;
 import java.security.PublicKey;
 import java.security.cert.Certificate;
@@ -163,14 +173,14 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
 
+import dalvik.system.DexFile;
+import dalvik.system.StaleDexCacheError;
 import dalvik.system.VMRuntime;
 import libcore.io.IoUtils;
 
-import com.android.internal.R;
-import com.android.server.pm.Settings.DatabaseVersion;
-import com.android.server.storage.DeviceStorageMonitorInternal;
-
 /**
  * Keep track of all those .apks everywhere.
  * 
@@ -197,6 +207,7 @@
     private static final boolean DEBUG_PACKAGE_SCANNING = false;
     private static final boolean DEBUG_APP_DIR_OBSERVER = false;
     private static final boolean DEBUG_VERIFY = false;
+    private static final boolean DEBUG_DEXOPT = false;
 
     private static final int RADIO_UID = Process.PHONE_UID;
     private static final int LOG_UID = Process.LOG_UID;
@@ -287,7 +298,6 @@
     final Context mContext;
     final boolean mFactoryTest;
     final boolean mOnlyCore;
-    final boolean mNoDexOpt;
     final DisplayMetrics mMetrics;
     final int mDefParseFlags;
     final String[] mSeparateProcesses;
@@ -593,6 +603,146 @@
 
     private final String mRequiredVerifierPackage;
 
+    private final PackageUsage mPackageUsage = new PackageUsage();
+
+    private class PackageUsage {
+        private static final int WRITE_INTERVAL
+            = (DEBUG_DEXOPT) ? 0 : 30*60*1000; // 30m in ms
+
+        private final Object mFileLock = new Object();
+        private final AtomicLong mLastWritten = new AtomicLong(0);
+        private final AtomicBoolean mBackgroundWriteRunning = new AtomicBoolean(false);
+
+        private boolean mIsFirstBoot = false;
+
+        boolean isFirstBoot() {
+            return mIsFirstBoot;
+        }
+
+        void write(boolean force) {
+            if (force) {
+                write();
+                return;
+            }
+            if (SystemClock.elapsedRealtime() - mLastWritten.get() < WRITE_INTERVAL
+                && !DEBUG_DEXOPT) {
+                return;
+            }
+            if (mBackgroundWriteRunning.compareAndSet(false, true)) {
+                new Thread("PackageUsage_DiskWriter") {
+                    @Override
+                    public void run() {
+                        try {
+                            write(true);
+                        } finally {
+                            mBackgroundWriteRunning.set(false);
+                        }
+                    }
+                }.start();
+            }
+        }
+
+        private void write() {
+            synchronized (mPackages) {
+                synchronized (mFileLock) {
+                    AtomicFile file = getFile();
+                    FileOutputStream f = null;
+                    try {
+                        f = file.startWrite();
+                        BufferedOutputStream out = new BufferedOutputStream(f);
+                        FileUtils.setPermissions(file.getBaseFile().getPath(), 0660, SYSTEM_UID, PACKAGE_INFO_GID);
+                        StringBuilder sb = new StringBuilder();
+                        for (PackageParser.Package pkg : mPackages.values()) {
+                            if (pkg.mLastPackageUsageTimeInMills == 0) {
+                                continue;
+                            }
+                            sb.setLength(0);
+                            sb.append(pkg.packageName);
+                            sb.append(' ');
+                            sb.append((long)pkg.mLastPackageUsageTimeInMills);
+                            sb.append('\n');
+                            out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
+                        }
+                        out.flush();
+                        file.finishWrite(f);
+                    } catch (IOException e) {
+                        if (f != null) {
+                            file.failWrite(f);
+                        }
+                        Log.e(TAG, "Failed to write package usage times", e);
+                    }
+                }
+            }
+            mLastWritten.set(SystemClock.elapsedRealtime());
+        }
+
+        void readLP() {
+            synchronized (mFileLock) {
+                AtomicFile file = getFile();
+                BufferedInputStream in = null;
+                try {
+                    in = new BufferedInputStream(file.openRead());
+                    StringBuffer sb = new StringBuffer();
+                    while (true) {
+                        String packageName = readToken(in, sb, ' ');
+                        if (packageName == null) {
+                            break;
+                        }
+                        String timeInMillisString = readToken(in, sb, '\n');
+                        if (timeInMillisString == null) {
+                            throw new IOException("Failed to find last usage time for package "
+                                                  + packageName);
+                        }
+                        PackageParser.Package pkg = mPackages.get(packageName);
+                        if (pkg == null) {
+                            continue;
+                        }
+                        long timeInMillis;
+                        try {
+                            timeInMillis = Long.parseLong(timeInMillisString.toString());
+                        } catch (NumberFormatException e) {
+                            throw new IOException("Failed to parse " + timeInMillisString
+                                                  + " as a long.", e);
+                        }
+                        pkg.mLastPackageUsageTimeInMills = timeInMillis;
+                    }
+                } catch (FileNotFoundException expected) {
+                    mIsFirstBoot = true;
+                } catch (IOException e) {
+                    Log.w(TAG, "Failed to read package usage times", e);
+                } finally {
+                    IoUtils.closeQuietly(in);
+                }
+            }
+            mLastWritten.set(SystemClock.elapsedRealtime());
+        }
+
+        private String readToken(InputStream in, StringBuffer sb, char endOfToken)
+                throws IOException {
+            sb.setLength(0);
+            while (true) {
+                int ch = in.read();
+                if (ch == -1) {
+                    if (sb.length() == 0) {
+                        return null;
+                    }
+                    throw new IOException("Unexpected EOF");
+                }
+                if (ch == endOfToken) {
+                    return sb.toString();
+                }
+                sb.append((char)ch);
+            }
+        }
+
+        private AtomicFile getFile() {
+            File dataDir = Environment.getDataDirectory();
+            File systemDir = new File(dataDir, "system");
+            File fname = new File(systemDir, "package-usage.list");
+            return new AtomicFile(fname);
+        }
+    }
+
     class PackageHandler extends Handler {
         private boolean mBound = false;
         final ArrayList<HandlerParams> mPendingInstalls =
@@ -1137,7 +1287,6 @@
         mContext = context;
         mFactoryTest = factoryTest;
         mOnlyCore = onlyCore;
-        mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
         mMetrics = new DisplayMetrics();
         mSettings = new Settings(context);
         mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
@@ -1223,10 +1372,6 @@
             // Set flag to monitor and not change apk file paths when
             // scanning install directories.
             int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
-            if (mNoDexOpt) {
-                Slog.w(TAG, "Running ENG build: no pre-dexopt!");
-                scanMode |= SCAN_NO_DEX;
-            }
 
             final HashSet<String> alreadyDexOpted = new HashSet<String>();
 
@@ -1245,7 +1390,7 @@
                 Slog.w(TAG, "No BOOTCLASSPATH found!");
             }
 
-            boolean didDexOpt = false;
+            boolean didDexOptLibraryOrTool = false;
 
             final List<String> instructionSets = getAllInstructionSets();
 
@@ -1265,13 +1410,12 @@
                         }
 
                         try {
-                            if (dalvik.system.DexFile.isDexOptNeededInternal(
-                                    lib, null, instructionSet, false)) {
+                            if (DexFile.isDexOptNeededInternal(lib, null, instructionSet, false)) {
                                 alreadyDexOpted.add(lib);
 
                                 // The list of "shared libraries" we have at this point is
                                 mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet);
-                                didDexOpt = true;
+                                didDexOptLibraryOrTool = true;
                             }
                         } catch (FileNotFoundException e) {
                             Slog.w(TAG, "Library not found: " + lib);
@@ -1317,9 +1461,9 @@
                             continue;
                         }
                         try {
-                            if (dalvik.system.DexFile.isDexOptNeededInternal(path, null, instructionSet, false)) {
+                            if (DexFile.isDexOptNeededInternal(path, null, instructionSet, false)) {
                                 mInstaller.dexopt(path, Process.SYSTEM_UID, true, instructionSet);
-                                didDexOpt = true;
+                                didDexOptLibraryOrTool = true;
                             }
                         } catch (FileNotFoundException e) {
                             Slog.w(TAG, "Jar not found: " + path);
@@ -1330,7 +1474,7 @@
                 }
             }
 
-            if (didDexOpt) {
+            if (didDexOptLibraryOrTool) {
                 pruneDexFiles(new File(dataDir, "dalvik-cache"));
             }
 
@@ -1509,12 +1653,15 @@
             // the correct library paths.
             updateAllSharedLibrariesLPw();
 
-
             for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
                 adjustCpuAbisForSharedUserLPw(setting.packages, true /* do dexopt */,
                         false /* force dexopt */, false /* defer dexopt */);
             }
 
+            // Now that we know all the packages we are keeping,
+            // read and update their last usage times.
+            mPackageUsage.readLP();
+
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                     SystemClock.uptimeMillis());
             Slog.i(TAG, "Time to scan packages: "
@@ -1573,6 +1720,14 @@
         //
         // Additionally, delete all dex files from the root directory
         // since there shouldn't be any there anyway.
+        //
+        // Note: This isn't as good an indicator as it used to be. It
+        // used to include the boot classpath but at some point
+        // DexFile.isDexOptNeeded started returning false for the boot
+        // class path files in all cases. It is very possible in a
+        // small maintenance release update that the library and tool
+        // jars may be unchanged but APK could be removed resulting in
+        // unused dalvik-cache files.
         File[] files = cacheDir.listFiles();
         if (files != null) {
             for (File file : files) {
@@ -1595,10 +1750,12 @@
         }
     }
 
+    @Override
     public boolean isFirstBoot() {
-        return !mRestoredSettings;
+        return !mRestoredSettings || mPackageUsage.isFirstBoot();
     }
 
+    @Override
     public boolean isOnlyCoreApps() {
         return mOnlyCore;
     }
@@ -1895,6 +2052,7 @@
                 state, userId);
     }
 
+    @Override
     public boolean isPackageAvailable(String packageName, int userId) {
         if (!sUserManager.exists(userId)) return false;
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "is package available");
@@ -1932,6 +2090,7 @@
         return null;
     }
 
+    @Override
     public String[] currentToCanonicalPackageNames(String[] names) {
         String[] out = new String[names.length];
         // reader
@@ -1944,6 +2103,7 @@
         return out;
     }
     
+    @Override
     public String[] canonicalToCurrentPackageNames(String[] names) {
         String[] out = new String[names.length];
         // reader
@@ -2004,6 +2164,7 @@
         return pi;
     }
     
+    @Override
     public PermissionInfo getPermissionInfo(String name, int flags) {
         // reader
         synchronized (mPackages) {
@@ -2015,6 +2176,7 @@
         }
     }
 
+    @Override
     public List<PermissionInfo> queryPermissionsByGroup(String group, int flags) {
         // reader
         synchronized (mPackages) {
@@ -2038,6 +2200,7 @@
         }
     }
 
+    @Override
     public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) {
         // reader
         synchronized (mPackages) {
@@ -2046,6 +2209,7 @@
         }
     }
 
+    @Override
     public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
         // reader
         synchronized (mPackages) {
@@ -2131,6 +2295,7 @@
     }
 
 
+    @Override
     public void freeStorageAndNotify(final long freeStorageSize, final IPackageDataObserver observer) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CLEAR_APP_CACHE, null);
@@ -2156,6 +2321,7 @@
         });
     }
 
+    @Override
     public void freeStorage(final long freeStorageSize, final IntentSender pi) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CLEAR_APP_CACHE, null);
@@ -2277,6 +2443,7 @@
         return null;
     }
 
+    @Override
     public String[] getSystemSharedLibraryNames() {
         Set<String> libSet;
         synchronized (mPackages) {
@@ -2291,6 +2458,7 @@
         return null;
     }
 
+    @Override
     public FeatureInfo[] getSystemAvailableFeatures() {
         Collection<FeatureInfo> featSet;
         synchronized (mPackages) {
@@ -2309,6 +2477,7 @@
         return null;
     }
 
+    @Override
     public boolean hasSystemFeature(String name) {
         synchronized (mPackages) {
             return mAvailableFeatures.containsKey(name);
@@ -2323,6 +2492,7 @@
                 + " is not privileged to communicate with user=" + userId);
     }
 
+    @Override
     public int checkPermission(String permName, String pkgName) {
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(pkgName);
@@ -2340,6 +2510,7 @@
         return PackageManager.PERMISSION_DENIED;
     }
 
+    @Override
     public int checkUidPermission(String permName, int uid) {
         synchronized (mPackages) {
             Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
@@ -2514,18 +2685,21 @@
         return added;
     }
 
+    @Override
     public boolean addPermission(PermissionInfo info) {
         synchronized (mPackages) {
             return addPermissionLocked(info, false);
         }
     }
 
+    @Override
     public boolean addPermissionAsync(PermissionInfo info) {
         synchronized (mPackages) {
             return addPermissionLocked(info, true);
         }
     }
 
+    @Override
     public void removePermission(String name) {
         synchronized (mPackages) {
             checkPermissionTreeLP(name);
@@ -2570,6 +2744,7 @@
         }
     }
 
+    @Override
     public void grantPermission(String packageName, String permissionName) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.GRANT_REVOKE_PERMISSIONS, null);
@@ -2599,6 +2774,7 @@
         }
     }
 
+    @Override
     public void revokePermission(String packageName, String permissionName) {
         int changedAppId = -1;
 
@@ -2657,12 +2833,14 @@
         }
     }
 
+    @Override
     public boolean isProtectedBroadcast(String actionName) {
         synchronized (mPackages) {
             return mProtectedBroadcasts.contains(actionName);
         }
     }
 
+    @Override
     public int checkSignatures(String pkg1, String pkg2) {
         synchronized (mPackages) {
             final PackageParser.Package p1 = mPackages.get(pkg1);
@@ -2675,6 +2853,7 @@
         }
     }
 
+    @Override
     public int checkUidSignatures(int uid1, int uid2) {
         // Map to base uids.
         uid1 = UserHandle.getAppId(uid1);
@@ -2814,6 +2993,7 @@
         return PackageManager.SIGNATURE_NO_MATCH;
     }
 
+    @Override
     public String[] getPackagesForUid(int uid) {
         uid = UserHandle.getAppId(uid);
         // reader
@@ -2837,6 +3017,7 @@
         return null;
     }
 
+    @Override
     public String getNameForUid(int uid) {
         // reader
         synchronized (mPackages) {
@@ -2852,6 +3033,7 @@
         return null;
     }
 
+    @Override
     public int getUidForSharedUser(String sharedUserName) {
         if(sharedUserName == null) {
             return -1;
@@ -2866,6 +3048,7 @@
         }
     }
 
+    @Override
     public int getFlagsForUid(int uid) {
         synchronized (mPackages) {
             Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
@@ -3797,6 +3980,7 @@
         }
     }
 
+    @Override
     public List<ProviderInfo> queryContentProviders(String processName,
             int uid, int flags) {
         ArrayList<ProviderInfo> finalList = null;
@@ -3834,6 +4018,7 @@
         return finalList;
     }
 
+    @Override
     public InstrumentationInfo getInstrumentationInfo(ComponentName name,
             int flags) {
         // reader
@@ -3843,6 +4028,7 @@
         }
     }
 
+    @Override
     public List<InstrumentationInfo> queryInstrumentation(String targetPackage,
             int flags) {
         ArrayList<InstrumentationInfo> finalList =
@@ -4289,21 +4475,60 @@
         }
 
         if (pkgs != null) {
+            // Filter out packages that aren't recently used.
+            //
+            // The exception is first boot of a non-eng device, which
+            // should do a full dexopt.
+            boolean eng = "eng".equals(SystemProperties.get("ro.build.type"));
+            if (eng || !isFirstBoot()) {
+                // TODO: add a property to control this?
+                long dexOptLRUThresholdInMinutes;
+                if (eng) {
+                    dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds.
+                } else {
+                    dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users.
+                }
+                long dexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000;
+
+                int total = pkgs.size();
+                int skipped = 0;
+                long now = System.currentTimeMillis();
+                for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
+                    PackageParser.Package pkg = i.next();
+                    long then = pkg.mLastPackageUsageTimeInMills;
+                    if (then + dexOptLRUThresholdInMills < now) {
+                        if (DEBUG_DEXOPT) {
+                            Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " +
+                                  ((then == 0) ? "never" : new Date(then)));
+                        }
+                        i.remove();
+                        skipped++;
+                    }
+                }
+                if (DEBUG_DEXOPT) {
+                    Log.i(TAG, "Skipped optimizing " + skipped + " of " + total);
+                }
+            }
+
             int i = 0;
             for (PackageParser.Package pkg : pkgs) {
+                i++;
+                if (DEBUG_DEXOPT) {
+                    Log.i(TAG, "Optimizing app " + i + " of " + pkgs.size()
+                          + ": " + pkg.packageName);
+                }
                 if (!isFirstBoot()) {
-                    i++;
                     try {
                         ActivityManagerNative.getDefault().showBootMessage(
                                 mContext.getResources().getString(
-                                        com.android.internal.R.string.android_upgrading_apk,
+                                        R.string.android_upgrading_apk,
                                         i, pkgs.size()), true);
                     } catch (RemoteException e) {
                     }
                 }
                 PackageParser.Package p = pkg;
                 synchronized (mInstallLock) {
-                    if (!p.mDidDexOpt) {
+                    if (p.mDexOptNeeded) {
                         performDexOptLI(p, false /* force dex */, false /* defer */,
                                 true /* include dependencies */);
                     }
@@ -4315,25 +4540,57 @@
     @Override
     public boolean performDexOpt(String packageName) {
         enforceSystemOrRoot("Only the system can request dexopt be performed");
-        if (!mNoDexOpt) {
-            return false;
-        }
+        return performDexOpt(packageName, true);
+    }
+
+    public boolean performDexOpt(String packageName, boolean updateUsage) {
 
         PackageParser.Package p;
         synchronized (mPackages) {
             p = mPackages.get(packageName);
-            if (p == null || p.mDidDexOpt) {
+            if (p == null) {
+                return false;
+            }
+            if (updateUsage) {
+                p.mLastPackageUsageTimeInMills = System.currentTimeMillis();
+            }
+            mPackageUsage.write();
+            if (!p.mDexOptNeeded) {
                 return false;
             }
         }
+
         synchronized (mInstallLock) {
             return performDexOptLI(p, false /* force dex */, false /* defer */,
                     true /* include dependencies */) == DEX_OPT_PERFORMED;
         }
     }
 
-    private void performDexOptLibsLI(ArrayList<String> libs, String instructionSet, boolean forceDex,
-            boolean defer, HashSet<String> done) {
+    public HashSet<String> getPackagesThatNeedDexOpt() {
+        HashSet<String> pkgs = null;
+        synchronized (mPackages) {
+            for (PackageParser.Package p : mPackages.values()) {
+                if (DEBUG_DEXOPT) {
+                    Log.i(TAG, p.packageName + " mDexOptNeeded=" + p.mDexOptNeeded);
+                }
+                if (!p.mDexOptNeeded) {
+                    continue;
+                }
+                if (pkgs == null) {
+                    pkgs = new HashSet<String>();
+                }
+                pkgs.add(p.packageName);
+            }
+        }
+        return pkgs;
+    }
+
+    public void shutdown() {
+        mPackageUsage.write(true);
+    }
+
+    private void performDexOptLibsLI(ArrayList<String> libs, String instructionSet,
+             boolean forceDex, boolean defer, HashSet<String> done) {
         for (int i=0; i<libs.size(); i++) {
             PackageParser.Package libPkg;
             String libName;
@@ -4358,8 +4615,7 @@
     static final int DEX_OPT_FAILED = -1;
 
     private int performDexOptLI(PackageParser.Package pkg, String instructionSetOverride,
-            boolean forceDex,
-            boolean defer, HashSet<String> done) {
+            boolean forceDex, boolean defer, HashSet<String> done) {
         final String instructionSet = instructionSetOverride != null ?
                 instructionSetOverride : getAppInstructionSet(pkg.applicationInfo);
 
@@ -4376,47 +4632,52 @@
         boolean performed = false;
         if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
             String path = pkg.mScanPath;
-            int ret = 0;
             try {
-                if (forceDex || dalvik.system.DexFile.isDexOptNeededInternal(path,
-                        pkg.packageName, instructionSet, defer)) {
-                    if (!forceDex && defer) {
-                        if (mDeferredDexOpt == null) {
-                            mDeferredDexOpt = new HashSet<PackageParser.Package>();
-                        }
-                        mDeferredDexOpt.add(pkg);
-                        return DEX_OPT_DEFERRED;
-                    } else {
-                        Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName +
-                                " (instructionSet=" + instructionSet + ")");
-
-                        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
-                        ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
+                boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
+                                                                                pkg.packageName,
+                                                                                instructionSet,
+                                                                                defer);
+                // There are three basic cases here:
+                // 1.) we need to dexopt, either because we are forced or it is needed
+                // 2.) we are defering a needed dexopt
+                // 3.) we are skipping an unneeded dexopt
+                if (forceDex || (!defer && isDexOptNeededInternal)) {
+                    Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
+                    final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+                    int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
                                                 pkg.packageName, instructionSet);
-                        pkg.mDidDexOpt = true;
-                        performed = true;
+                    // Note that we ran dexopt, since rerunning will
+                    // probably just result in an error again.
+                    pkg.mDexOptNeeded = false;
+                    if (ret < 0) {
+                        return DEX_OPT_FAILED;
                     }
+                    return DEX_OPT_PERFORMED;
                 }
+                if (defer && isDexOptNeededInternal) {
+                    if (mDeferredDexOpt == null) {
+                        mDeferredDexOpt = new HashSet<PackageParser.Package>();
+                    }
+                    mDeferredDexOpt.add(pkg);
+                    return DEX_OPT_DEFERRED;
+                }
+                pkg.mDexOptNeeded = false;
+                return DEX_OPT_SKIPPED;
             } catch (FileNotFoundException e) {
                 Slog.w(TAG, "Apk not found for dexopt: " + path);
-                ret = -1;
+                return DEX_OPT_FAILED;
             } catch (IOException e) {
                 Slog.w(TAG, "IOException reading apk: " + path, e);
-                ret = -1;
-            } catch (dalvik.system.StaleDexCacheError e) {
+                return DEX_OPT_FAILED;
+            } catch (StaleDexCacheError e) {
                 Slog.w(TAG, "StaleDexCacheError when reading apk: " + path, e);
-                ret = -1;
+                return DEX_OPT_FAILED;
             } catch (Exception e) {
                 Slog.w(TAG, "Exception when doing dexopt : ", e);
-                ret = -1;
-            }
-            if (ret < 0) {
-                //error from installer
                 return DEX_OPT_FAILED;
             }
         }
-
-        return performed ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
+        return DEX_OPT_SKIPPED;
     }
 
     private String getAppInstructionSet(ApplicationInfo info) {
@@ -4705,7 +4966,7 @@
                     mResolveActivity.processName = "system:ui";
                     mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
                     mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
-                    mResolveActivity.theme = com.android.internal.R.style.Theme_Holo_Dialog_Alert;
+                    mResolveActivity.theme = R.style.Theme_Holo_Dialog_Alert;
                     mResolveActivity.exported = true;
                     mResolveActivity.enabled = true;
                     mResolveInfo.activityInfo = mResolveActivity;
@@ -7064,6 +7325,7 @@
         return mMediaMounted || Environment.isExternalStorageEmulated();
     }
 
+    @Override
     public PackageCleanItem nextPackageToClean(PackageCleanItem lastPackage) {
         // writer
         synchronized (mPackages) {
@@ -7249,6 +7511,7 @@
     }
 
     /* Called when a downloaded package installation has been confirmed by the user */
+    @Override
     public void installPackage(
             final Uri packageURI, final IPackageInstallObserver observer, final int flags,
             final String installerPackageName) {
@@ -7266,6 +7529,7 @@
                 installerPackageName, verificationParams, encryptionParams);
     }
 
+    @Override
     public void installPackageWithVerificationAndEncryption(Uri packageURI,
             IPackageInstallObserver observer, int flags, String installerPackageName,
             VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
@@ -7675,6 +7939,7 @@
         }
     }
 
+    @Override
     public void finishPackageInstall(int token) {
         enforceSystemOrRoot("Only the system is allowed to finish installs");
 
@@ -7746,6 +8011,7 @@
                 -1);
     }
 
+    @Override
     public void setInstallerPackageName(String targetPackage, String installerPackageName) {
         final int uid = Binder.getCallingUid();
         // writer
@@ -9701,22 +9967,22 @@
 
     // Utility method used to move dex files during install.
     private int moveDexFilesLI(PackageParser.Package newPackage) {
-        int retCode;
         if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
-            retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath,
-                    getAppInstructionSet(newPackage.applicationInfo));
+            final String instructionSet = getAppInstructionSet(newPackage.applicationInfo);
+            int retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath,
+                                             instructionSet);
             if (retCode != 0) {
-                if (mNoDexOpt) {
-                    /*
-                     * If we're in an engineering build, programs are lazily run
-                     * through dexopt. If the .dex file doesn't exist yet, it
-                     * will be created when the program is run next.
-                     */
-                    Slog.i(TAG, "dex file doesn't exist, skipping move: " + newPackage.mPath);
-                } else {
-                    Slog.e(TAG, "Couldn't rename dex file: " + newPackage.mPath);
-                    return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                }
+                /*
+                 * Programs may be lazily run through dexopt, so the
+                 * source may not exist. However, something seems to
+                 * have gone wrong, so note that dexopt needs to be
+                 * run again and remove the source file. In addition,
+                 * remove the target to make sure there isn't a stale
+                 * file from a previous version of the package.
+                 */
+                newPackage.mDexOptNeeded = true;
+                mInstaller.rmdex(newPackage.mScanPath, instructionSet);
+                mInstaller.rmdex(newPackage.mPath, instructionSet);
             }
         }
         return PackageManager.INSTALL_SUCCEEDED;
@@ -10680,6 +10946,7 @@
         }
     }
 
+    @Override
     public void deleteApplicationCacheFiles(final String packageName,
             final IPackageDataObserver observer) {
         mContext.enforceCallingOrSelfPermission(
@@ -10732,6 +10999,7 @@
         return true;
     }
 
+    @Override
     public void getPackageSizeInfo(final String packageName, int userHandle,
             final IPackageStatsObserver observer) {
         mContext.enforceCallingOrSelfPermission(
@@ -10811,14 +11079,17 @@
     }
 
 
+    @Override
     public void addPackageToPreferred(String packageName) {
         Slog.w(TAG, "addPackageToPreferred: this is now a no-op");
     }
 
+    @Override
     public void removePackageFromPreferred(String packageName) {
         Slog.w(TAG, "removePackageFromPreferred: this is now a no-op");
     }
 
+    @Override
     public List<PackageInfo> getPreferredPackages(int flags) {
         return new ArrayList<PackageInfo>();
     }
@@ -10846,6 +11117,7 @@
         return Build.VERSION_CODES.CUR_DEVELOPMENT;
     }
 
+    @Override
     public void addPreferredActivity(IntentFilter filter, int match,
             ComponentName[] set, ComponentName activity, int userId) {
         addPreferredActivityInternal(filter, match, set, activity, true, userId);
@@ -10882,6 +11154,7 @@
         }
     }
 
+    @Override
     public void replacePreferredActivity(IntentFilter filter, int match,
             ComponentName[] set, ComponentName activity) {
         if (filter.countActions() != 1) {
@@ -10938,6 +11211,7 @@
         }
     }
 
+    @Override
     public void clearPackagePreferredActivities(String packageName) {
         final int uid = Binder.getCallingUid();
         // writer
@@ -11001,6 +11275,7 @@
         return changed;
     }
 
+    @Override
     public void resetPreferredActivities(int userId) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
@@ -11014,6 +11289,7 @@
         }
     }
 
+    @Override
     public int getPreferredActivities(List<IntentFilter> outFilters,
             List<ComponentName> outActivities, String packageName) {
 
@@ -11321,6 +11597,7 @@
                 new int[] {UserHandle.getUserId(packageUid)});
     }
 
+    @Override
     public void setPackageStoppedState(String packageName, boolean stopped, int userId) {
         if (!sUserManager.exists(userId)) return;
         final int uid = Binder.getCallingUid();
@@ -11337,6 +11614,7 @@
         }
     }
 
+    @Override
     public String getInstallerPackageName(String packageName) {
         // reader
         synchronized (mPackages) {
@@ -11366,6 +11644,7 @@
         }
     }
 
+    @Override
     public void enterSafeMode() {
         enforceSystemOrRoot("Only the system can request entering safe mode");
 
@@ -11374,6 +11653,7 @@
         }
     }
 
+    @Override
     public void systemReady() {
         mSystemReady = true;
 
@@ -11419,10 +11699,12 @@
         sUserManager.systemReady();
     }
 
+    @Override
     public boolean isSafeMode() {
         return mSafeMode;
     }
 
+    @Override
     public boolean hasSystemUidErrors() {
         return mHasSystemUidErrors;
     }
@@ -11920,6 +12202,7 @@
     /*
      * Update media status on PackageManager.
      */
+    @Override
     public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
         int callingUid = Binder.getCallingUid();
         if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
@@ -12514,6 +12797,7 @@
         });
     }
 
+    @Override
     public boolean setInstallLocation(int loc) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
                 null);
@@ -12529,6 +12813,7 @@
         return false;
    }
 
+    @Override
     public int getInstallLocation() {
         return android.provider.Settings.Global.getInt(mContext.getContentResolver(),
                 android.provider.Settings.Global.DEFAULT_INSTALL_LOCATION,
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 4f5326f..60212bf 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -288,6 +288,20 @@
         return users;
     }
 
+    @Override
+    public UserInfo getProfileParent(int userHandle) {
+        checkManageUsersPermission("get the profile parent");
+        synchronized (mPackagesLock) {
+            UserInfo profile = getUserInfoLocked(userHandle);
+            int parentUserId = profile.profileGroupId;
+            if (parentUserId == UserInfo.NO_PROFILE_GROUP_ID) {
+                return null;
+            } else {
+                return getUserInfoLocked(parentUserId);
+            }
+        }
+    }
+
     private boolean isProfileOf(UserInfo user, UserInfo profile) {
         return user.id == profile.id ||
                 (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
@@ -743,6 +757,9 @@
                 writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
                 writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
                 writeBoolean(serializer, restrictions, UserManager.DISALLOW_CONFIG_APPS);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_UNMUTE_MICROPHONE);
+                writeBoolean(serializer, restrictions, UserManager.DISALLOW_ADJUST_VOLUME);
                 serializer.endTag(null, TAG_RESTRICTIONS);
             }
             serializer.endTag(null, TAG_USER);
@@ -891,6 +908,10 @@
                         readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
                         readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
                         readBoolean(parser, restrictions, UserManager.DISALLOW_CONFIG_APPS);
+                        readBoolean(parser, restrictions,
+                                UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_UNMUTE_MICROPHONE);
+                        readBoolean(parser, restrictions, UserManager.DISALLOW_ADJUST_VOLUME);
                     }
                 }
             }
@@ -1015,17 +1036,6 @@
         }
     }
 
-    private int getNextProfileGroupIdLocked() {
-        int maxGroupId = UserInfo.NO_PROFILE_GROUP_ID;
-        for (int i = 0; i < mUsers.size(); i++) {
-            UserInfo ui = mUsers.valueAt(i);
-            if (maxGroupId < ui.profileGroupId) {
-                maxGroupId = ui.profileGroupId;
-            }
-        }
-        return maxGroupId + 1;
-    }
-
     @Override
     public UserInfo createProfileForUser(String name, int flags, int userId) {
         checkManageUsersPermission("Only the system can create users");
@@ -1042,16 +1052,16 @@
         return createUserInternal(name, flags, UserHandle.USER_NULL);
     }
 
-    private UserInfo createUserInternal(String name, int flags, int profileId) {
+    private UserInfo createUserInternal(String name, int flags, int parentId) {
         final long ident = Binder.clearCallingIdentity();
         UserInfo userInfo = null;
         try {
             synchronized (mInstallLock) {
                 synchronized (mPackagesLock) {
-                    UserInfo profile = null;
-                    if (profileId != UserHandle.USER_NULL) {
-                        profile = getUserInfoLocked(profileId);
-                        if (profile == null) return null;
+                    UserInfo parent = null;
+                    if (parentId != UserHandle.USER_NULL) {
+                        parent = getUserInfoLocked(parentId);
+                        if (parent == null) return null;
                     }
                     if (isUserLimitReachedLocked()) return null;
                     int userId = getNextAvailableIdLocked();
@@ -1064,12 +1074,12 @@
                     Environment.getUserSystemDirectory(userInfo.id).mkdirs();
                     mUsers.put(userId, userInfo);
                     writeUserListLocked();
-                    if (profile != null) {
-                        if (profile.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
-                            profile.profileGroupId = getNextProfileGroupIdLocked();
-                            writeUserLocked(profile);
+                    if (parent != null) {
+                        if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
+                            parent.profileGroupId = parent.id;
+                            writeUserLocked(parent);
                         }
-                        userInfo.profileGroupId = profile.profileGroupId;
+                        userInfo.profileGroupId = parent.profileGroupId;
                     }
                     writeUserLocked(userInfo);
                     mPm.createNewUserLILPw(userId, userPath);
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 6d2e8592..47a8b2e 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1634,6 +1634,8 @@
 
             mDisplayPowerRequest.blockScreenOn = mScreenOnBlocker.isHeld();
 
+            mDisplayPowerRequest.lowPowerMode = mLowPowerModeEnabled;
+
             mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
                     mRequestWaitForNegativeProximity);
             mRequestWaitForNegativeProximity = false;
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 8fed79f..956e3e6 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -45,6 +45,7 @@
 import android.os.storage.IMountShutdownObserver;
 
 import com.android.internal.telephony.ITelephony;
+import com.android.server.pm.PackageManagerService;
 
 import android.util.Log;
 import android.view.WindowManager;
@@ -329,6 +330,14 @@
             }
         }
 
+        Log.i(TAG, "Shutting down package manager...");
+
+        final PackageManagerService pm = (PackageManagerService)
+            ServiceManager.getService("package");
+        if (pm != null) {
+            pm.shutdown();
+        }
+
         // Shutdown radios.
         shutdownRadios(MAX_RADIO_WAIT_TIME);
 
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 9039236..99ec242 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -116,7 +116,8 @@
     /** Fraction of animation at which the recents thumbnail becomes completely transparent */
     private static final float RECENTS_THUMBNAIL_FADEOUT_FRACTION = 0.25f;
 
-    private static final long DEFAULT_APP_TRANSITION_DURATION = 250;
+    private static final int DEFAULT_APP_TRANSITION_DURATION = 250;
+    private static final int THUMBNAIL_APP_TRANSITION_DURATION = 225;
 
     private final Context mContext;
     private final Handler mH;
@@ -160,6 +161,7 @@
     private final int mConfigShortAnimTime;
     private final Interpolator mDecelerateInterpolator;
     private final Interpolator mThumbnailFadeoutInterpolator;
+    private final Interpolator mThumbnailCubicInterpolator;
 
     private int mCurrentUserId = 0;
 
@@ -170,6 +172,8 @@
                 com.android.internal.R.integer.config_shortAnimTime);
         mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.decelerate_cubic);
+        mThumbnailCubicInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
         mThumbnailFadeoutInterpolator = new Interpolator() {
             @Override
             public float getInterpolation(float input) {
@@ -401,11 +405,23 @@
     /**
      * Prepares the specified animation with a standard duration, interpolator, etc.
      */
+    Animation prepareThumbnailAnimationWithDuration(Animation a, int appWidth, int appHeight,
+            int duration, Interpolator interpolator) {
+        a.setDuration(duration);
+        a.setFillAfter(true);
+        a.setInterpolator(interpolator);
+        a.initialize(appWidth, appHeight, appWidth, appHeight);
+        return a;
+    }
+
+    /**
+     * Prepares the specified animation with a standard duration, interpolator, etc.
+     */
     Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
         // Pick the desired duration.  If this is an inter-activity transition,
         // it  is the standard duration for that.  Otherwise we use the longer
         // task transition duration.
-        final long duration;
+        final int duration;
         switch (transit) {
             case TRANSIT_ACTIVITY_OPEN:
             case TRANSIT_ACTIVITY_CLOSE:
@@ -415,11 +431,8 @@
                 duration = DEFAULT_APP_TRANSITION_DURATION;
                 break;
         }
-        a.setDuration(duration);
-        a.setFillAfter(true);
-        a.setInterpolator(mDecelerateInterpolator);
-        a.initialize(appWidth, appHeight, appWidth, appHeight);
-        return a;
+        return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight, duration,
+                mDecelerateInterpolator);
     }
 
     /**
@@ -594,7 +607,8 @@
                 throw new RuntimeException("Invalid thumbnail transition state");
         }
 
-        return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
+        return prepareThumbnailAnimationWithDuration(a, appWidth, appHeight,
+                THUMBNAIL_APP_TRANSITION_DURATION, mThumbnailCubicInterpolator);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 637beec..836a19c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5038,6 +5038,10 @@
             throw new SecurityException("Requires DISABLE_KEYGUARD permission");
         }
 
+        if (token == null) {
+            throw new IllegalArgumentException("token == null");
+        }
+
         mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
                 KeyguardDisableHandler.KEYGUARD_DISABLE, new Pair<IBinder, String>(token, tag)));
     }
@@ -5049,6 +5053,10 @@
             throw new SecurityException("Requires DISABLE_KEYGUARD permission");
         }
 
+        if (token == null) {
+            throw new IllegalArgumentException("token == null");
+        }
+
         mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
                 KeyguardDisableHandler.KEYGUARD_REENABLE, token));
     }
@@ -5062,6 +5070,11 @@
             != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Requires DISABLE_KEYGUARD permission");
         }
+
+        if (callback == null) {
+            throw new IllegalArgumentException("callback == null");
+        }
+
         mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() {
             @Override
             public void onKeyguardExitResult(boolean success) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4318b0e..e746c1a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -299,6 +299,7 @@
 
     boolean mHasSurface = false;
 
+    boolean mNotOnAppsDisplay = false;
     DisplayContent  mDisplayContent;
 
     /** When true this window can be displayed on screens owther than mOwnerUid's */
@@ -430,6 +431,10 @@
         }
         mRootToken = appToken;
         mAppToken = appToken.appWindowToken;
+        if (mAppToken != null) {
+            final DisplayContent appDisplay = getDisplayContent();
+            mNotOnAppsDisplay = displayContent != appDisplay;
+        }
 
         mWinAnimator = new WindowStateAnimator(this);
         mWinAnimator.mAlpha = a.alpha;
@@ -717,7 +722,8 @@
     }
 
     public DisplayContent getDisplayContent() {
-        return mAppToken == null ? mDisplayContent : getStack().getDisplayContent();
+        return mAppToken == null || mNotOnAppsDisplay ?
+                mDisplayContent : getStack().getDisplayContent();
     }
 
     public int getDisplayId() {
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
index 163692b..163225e 100644
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -46,33 +46,16 @@
 // ----------------------------------------------------------------------------
 
 static struct {
-    jfieldID mFinalizer;
-    jfieldID mNativeCanvas;
+    jmethodID safeCanvasSwap;
 } gCanvasClassInfo;
 
-static struct {
-    jfieldID mNativeCanvas;
-} gCanvasFinalizerClassInfo;
-
-#define GET_LONG(object, field) \
-    env->GetLongField(object, field)
-
-#define SET_LONG(object, field, value) \
-    env->SetLongField(object, field, value)
+#define INVOKEV(object, method, ...) \
+    env->CallVoidMethod(object, method, __VA_ARGS__)
 
 // ----------------------------------------------------------------------------
 // Canvas management
 // ----------------------------------------------------------------------------
 
-static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
-    jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
-    SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
-            GET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas));
-    SET_LONG(canvasObj, gCanvasClassInfo.mNativeCanvas, (long) newCanvas);
-    SET_LONG(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (long) newCanvas);
-    SkSafeUnref(previousCanvas);
-}
-
 static jlong com_android_server_AssetAtlasService_acquireCanvas(JNIEnv* env, jobject,
         jobject canvas, jint width, jint height) {
 
@@ -82,7 +65,7 @@
     bitmap->eraseColor(0);
 
     SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (*bitmap));
-    swapCanvasPtr(env, canvas, nativeCanvas);
+    INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     return reinterpret_cast<jlong>(bitmap);
 }
@@ -92,7 +75,7 @@
 
     SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
     SkCanvas* nativeCanvas = SkNEW(SkCanvas);
-    swapCanvasPtr(env, canvas, nativeCanvas);
+    INVOKEV(canvas, gCanvasClassInfo.safeCanvasSwap, (jlong)nativeCanvas, false);
 
     delete bitmap;
 }
@@ -242,9 +225,9 @@
         var = env->FindClass(className); \
         LOG_FATAL_IF(! var, "Unable to find class " className);
 
-#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
-        var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
-        LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
+        var = env->GetMethodID(clazz, methodName, methodDescriptor); \
+        LOG_FATAL_IF(!var, "Unable to find method " methodName);
 
 const char* const kClassPathName = "com/android/server/AssetAtlasService";
 
@@ -261,12 +244,7 @@
     jclass clazz;
 
     FIND_CLASS(clazz, "android/graphics/Canvas");
-    GET_FIELD_ID(gCanvasClassInfo.mFinalizer, clazz, "mFinalizer",
-            "Landroid/graphics/Canvas$CanvasFinalizer;");
-    GET_FIELD_ID(gCanvasClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
-
-    FIND_CLASS(clazz, "android/graphics/Canvas$CanvasFinalizer");
-    GET_FIELD_ID(gCanvasFinalizerClassInfo.mNativeCanvas, clazz, "mNativeCanvas", "J");
+    GET_METHOD_ID(gCanvasClassInfo.safeCanvasSwap, clazz, "safeCanvasSwap", "(JZ)V");
 
     return jniRegisterNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 23b912f..1980d1e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -50,7 +50,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
-import android.net.ProxyProperties;
+import android.net.ProxyInfo;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
@@ -97,9 +97,11 @@
 import java.security.cert.X509Certificate;
 import java.text.DateFormat;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -112,6 +114,8 @@
 
     private static final String DEVICE_POLICIES_XML = "device_policies.xml";
 
+    private static final String LOCK_TASK_COMPONENTS_XML = "lock-task-component";
+
     private static final int REQUEST_EXPIRE_PASSWORD = 5571;
 
     private static final long MS_PER_DAY = 86400 * 1000;
@@ -126,6 +130,7 @@
     private static final boolean DBG = false;
 
     final Context mContext;
+    final UserManager mUserManager;
     final PowerManager.WakeLock mWakeLock;
 
     IPowerManager mIPowerManager;
@@ -181,6 +186,9 @@
         final ArrayList<ActiveAdmin> mAdminList
                 = new ArrayList<ActiveAdmin>();
 
+        // This is the list of component allowed to start lock task mode.
+        final List<ComponentName> mLockTaskComponents = new ArrayList<ComponentName>();
+
         public DevicePolicyData(int userHandle) {
             mUserHandle = userHandle;
         }
@@ -202,7 +210,7 @@
                         + action + " for user " + userHandle);
                 mHandler.post(new Runnable() {
                     public void run() {
-                        handlePasswordExpirationNotification(getUserData(userHandle));
+                        handlePasswordExpirationNotification(userHandle);
                     }
                 });
             }
@@ -232,6 +240,8 @@
     static class ActiveAdmin {
         private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
         private static final String TAG_DISABLE_CAMERA = "disable-camera";
+        private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management";
+        private static final String TAG_ACCOUNT_TYPE = "account-type";
         private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested";
         private static final String TAG_PASSWORD_EXPIRATION_DATE = "password-expiration-date";
         private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password-expiration-timeout";
@@ -297,6 +307,7 @@
 
         boolean encryptionRequested = false;
         boolean disableCamera = false;
+        Set<String> accountTypesWithManagementDisabled = new HashSet<String>();
 
         // TODO: review implementation decisions with frameworks team
         boolean specifiesGlobalProxy = false;
@@ -413,6 +424,15 @@
                 out.attribute(null, ATTR_VALUE, Integer.toString(disabledKeyguardFeatures));
                 out.endTag(null, TAG_DISABLE_KEYGUARD_FEATURES);
             }
+            if (!accountTypesWithManagementDisabled.isEmpty()) {
+                out.startTag(null, TAG_DISABLE_ACCOUNT_MANAGEMENT);
+                for (String ac : accountTypesWithManagementDisabled) {
+                    out.startTag(null, TAG_ACCOUNT_TYPE);
+                    out.attribute(null, ATTR_VALUE, ac);
+                    out.endTag(null, TAG_ACCOUNT_TYPE);
+                }
+                out.endTag(null,  TAG_DISABLE_ACCOUNT_MANAGEMENT);
+            }
         }
 
         void readFromXml(XmlPullParser parser)
@@ -484,6 +504,23 @@
                 } else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) {
                     disabledKeyguardFeatures = Integer.parseInt(
                             parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_DISABLE_ACCOUNT_MANAGEMENT.equals(tag)) {
+                    int outerDepthDAM = parser.getDepth();
+                    int typeDAM;
+                    while ((typeDAM=parser.next()) != XmlPullParser.END_DOCUMENT
+                            && (typeDAM != XmlPullParser.END_TAG
+                                    || parser.getDepth() > outerDepthDAM)) {
+                        if (typeDAM == XmlPullParser.END_TAG || typeDAM == XmlPullParser.TEXT) {
+                            continue;
+                        }
+                        String tagDAM = parser.getName();
+                        if (TAG_ACCOUNT_TYPE.equals(tagDAM)) {
+                            accountTypesWithManagementDisabled.add(
+                                    parser.getAttributeValue(null, ATTR_VALUE));
+                        } else {
+                            Slog.w(LOG_TAG, "Unknown tag under " + tag +  ": " + tagDAM);
+                        }
+                    }
                 } else {
                     Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                 }
@@ -575,6 +612,7 @@
      */
     public DevicePolicyManagerService(Context context) {
         mContext = context;
+        mUserManager = UserManager.get(mContext);
         mHasFeature = context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_DEVICE_ADMIN);
         mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
@@ -782,6 +820,9 @@
         sendAdminCommandLocked(admin, action, null);
     }
 
+    /**
+     * Send an update to one specific admin, get notified when that admin returns a result.
+     */
     void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
         Intent intent = new Intent(action);
         intent.setComponent(admin.info.getComponent());
@@ -796,12 +837,15 @@
         }
     }
 
+    /**
+     * Send an update to all admins of a user that enforce a specified policy.
+     */
     void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) {
         final DevicePolicyData policy = getUserData(userHandle);
         final int count = policy.mAdminList.size();
         if (count > 0) {
             for (int i = 0; i < count; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
+                final ActiveAdmin admin = policy.mAdminList.get(i);
                 if (admin.info.usesPolicy(reqPolicy)) {
                     sendAdminCommandLocked(admin, action);
                 }
@@ -809,6 +853,19 @@
         }
     }
 
+    /**
+     * Send an update intent to all admins of a user and its profiles. Only send to admins that
+     * enforce a specified policy.
+     */
+    private void sendAdminCommandToSelfAndProfilesLocked(String action, int reqPolicy,
+            int userHandle) {
+        List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+        for (UserInfo ui : profiles) {
+            int id = ui.getUserHandle().getIdentifier();
+            sendAdminCommandLocked(action, reqPolicy, id);
+        }
+    }
+
     void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
         final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
         if (admin != null) {
@@ -925,6 +982,13 @@
                 out.endTag(null, "active-password");
             }
 
+            for (int i=0; i<policy.mLockTaskComponents.size(); i++) {
+                ComponentName component = policy.mLockTaskComponents.get(i);
+                out.startTag(null, LOCK_TASK_COMPONENTS_XML);
+                out.attribute(null, "name", component.flattenToString());
+                out.endTag(null, LOCK_TASK_COMPONENTS_XML);
+            }
+
             out.endTag(null, "policies");
 
             out.endDocument();
@@ -974,6 +1038,7 @@
             }
             type = parser.next();
             int outerDepth = parser.getDepth();
+            policy.mLockTaskComponents.clear();
             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -1026,6 +1091,11 @@
                     policy.mActivePasswordNonLetter = Integer.parseInt(
                             parser.getAttributeValue(null, "nonletter"));
                     XmlUtils.skipCurrentTag(parser);
+                } else if (LOCK_TASK_COMPONENTS_XML.equals(tag)) {
+                    policy.mLockTaskComponents.add
+                        (ComponentName.unflattenFromString
+                         (parser.getAttributeValue(null, "name")));
+                    XmlUtils.skipCurrentTag(parser);
                 } else {
                     Slog.w(LOG_TAG, "Unknown tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -1141,23 +1211,29 @@
         }
     }
 
-    private void handlePasswordExpirationNotification(DevicePolicyData policy) {
+    private void handlePasswordExpirationNotification(int userHandle) {
         synchronized (this) {
             final long now = System.currentTimeMillis();
-            final int N = policy.mAdminList.size();
-            if (N <= 0) {
-                return;
-            }
-            for (int i=0; i < N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
-                        && admin.passwordExpirationTimeout > 0L
-                        && admin.passwordExpirationDate > 0L
-                        && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
-                    sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
+
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo ui : profiles) {
+                int profileUserHandle = ui.getUserHandle().getIdentifier();
+                final DevicePolicyData policy = getUserData(profileUserHandle);
+                final int count = policy.mAdminList.size();
+                if (count > 0) {
+                    for (int i = 0; i < count; i++) {
+                        final ActiveAdmin admin = policy.mAdminList.get(i);
+                        if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
+                                && admin.passwordExpirationTimeout > 0L
+                                && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS
+                                && admin.passwordExpirationDate > 0L) {
+                            sendAdminCommandLocked(admin,
+                                    DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
+                        }
+                    }
                 }
             }
-            setExpirationAlarmCheckLocked(mContext, policy);
+            setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
         }
     }
 
@@ -1167,8 +1243,7 @@
         final boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
         if (! hasCert) {
             if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
-                UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-                for (UserInfo user : um.getUsers()) {
+                for (UserInfo user : mUserManager.getUsers()) {
                     notificationManager.cancelAsUser(
                             null, MONITORING_CERT_NOTIFICATION_ID, user.getUserHandle());
                 }
@@ -1207,8 +1282,7 @@
         // If this is a boot intent, this will fire for each user. But if this is a storage changed
         // intent, it will fire once, so we need to notify all users.
         if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
-            UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-            for (UserInfo user : um.getUsers()) {
+            for (UserInfo user : mUserManager.getUsers()) {
                 notificationManager.notifyAsUser(
                         null, MONITORING_CERT_NOTIFICATION_ID, noti, user.getUserHandle());
             }
@@ -1385,18 +1459,22 @@
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
             int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
-            DevicePolicyData policy = getUserData(userHandle);
 
             if (who != null) {
                 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
                 return admin != null ? admin.passwordQuality : mode;
             }
 
-            final int N = policy.mAdminList.size();
-            for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (mode < admin.passwordQuality) {
-                    mode = admin.passwordQuality;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (mode < admin.passwordQuality) {
+                        mode = admin.passwordQuality;
+                    }
                 }
             }
             return mode;
@@ -1427,7 +1505,6 @@
         }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
-            DevicePolicyData policy = getUserData(userHandle);
             int length = 0;
 
             if (who != null) {
@@ -1435,11 +1512,16 @@
                 return admin != null ? admin.minimumPasswordLength : length;
             }
 
-            final int N = policy.mAdminList.size();
-            for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.minimumPasswordLength) {
-                    length = admin.minimumPasswordLength;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.minimumPasswordLength) {
+                        length = admin.minimumPasswordLength;
+                    }
                 }
             }
             return length;
@@ -1470,7 +1552,6 @@
         }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
-            DevicePolicyData policy = getUserData(userHandle);
             int length = 0;
 
             if (who != null) {
@@ -1478,11 +1559,16 @@
                 return admin != null ? admin.passwordHistoryLength : length;
             }
 
-            final int N = policy.mAdminList.size();
-            for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.passwordHistoryLength) {
-                    length = admin.passwordHistoryLength;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i = 0; i < N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.passwordHistoryLength) {
+                        length = admin.passwordHistoryLength;
+                    }
                 }
             }
             return length;
@@ -1528,19 +1614,23 @@
         }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
+            long timeout = 0L;
+
             if (who != null) {
                 ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
-                return admin != null ? admin.passwordExpirationTimeout : 0L;
+                return admin != null ? admin.passwordExpirationTimeout : timeout;
             }
 
-            long timeout = 0L;
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
-                        && timeout > admin.passwordExpirationTimeout)) {
-                    timeout = admin.passwordExpirationTimeout;
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i = 0; i < N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
+                            && timeout > admin.passwordExpirationTimeout)) {
+                        timeout = admin.passwordExpirationTimeout;
+                    }
                 }
             }
             return timeout;
@@ -1552,19 +1642,23 @@
      * Returns 0 if not configured.
      */
     private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
+        long timeout = 0L;
+
         if (who != null) {
             ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
-            return admin != null ? admin.passwordExpirationDate : 0L;
+            return admin != null ? admin.passwordExpirationDate : timeout;
         }
 
-        long timeout = 0L;
-        DevicePolicyData policy = getUserData(userHandle);
-        final int N = policy.mAdminList.size();
-        for (int i = 0; i < N; i++) {
-            ActiveAdmin admin = policy.mAdminList.get(i);
-            if (timeout == 0L || (admin.passwordExpirationDate != 0
-                    && timeout > admin.passwordExpirationDate)) {
-                timeout = admin.passwordExpirationDate;
+        List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+        for (UserInfo userInfo : profiles) {
+            DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+            final int N = policy.mAdminList.size();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = policy.mAdminList.get(i);
+                if (timeout == 0L || (admin.passwordExpirationDate != 0
+                        && timeout > admin.passwordExpirationDate)) {
+                    timeout = admin.passwordExpirationDate;
+                }
             }
         }
         return timeout;
@@ -1611,12 +1705,16 @@
                 return admin != null ? admin.minimumPasswordUpperCase : length;
             }
 
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.minimumPasswordUpperCase) {
-                    length = admin.minimumPasswordUpperCase;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.minimumPasswordUpperCase) {
+                        length = admin.minimumPasswordUpperCase;
+                    }
                 }
             }
             return length;
@@ -1651,12 +1749,16 @@
                 return admin != null ? admin.minimumPasswordLowerCase : length;
             }
 
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.minimumPasswordLowerCase) {
-                    length = admin.minimumPasswordLowerCase;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.minimumPasswordLowerCase) {
+                        length = admin.minimumPasswordLowerCase;
+                    }
                 }
             }
             return length;
@@ -1694,12 +1796,16 @@
                 return admin != null ? admin.minimumPasswordLetters : length;
             }
 
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.minimumPasswordLetters) {
-                    length = admin.minimumPasswordLetters;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.minimumPasswordLetters) {
+                        length = admin.minimumPasswordLetters;
+                    }
                 }
             }
             return length;
@@ -1737,12 +1843,16 @@
                 return admin != null ? admin.minimumPasswordNumeric : length;
             }
 
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for (int i = 0; i < N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.minimumPasswordNumeric) {
-                    length = admin.minimumPasswordNumeric;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i = 0; i < N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.minimumPasswordNumeric) {
+                        length = admin.minimumPasswordNumeric;
+                    }
                 }
             }
             return length;
@@ -1780,12 +1890,16 @@
                 return admin != null ? admin.minimumPasswordSymbols : length;
             }
 
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.minimumPasswordSymbols) {
-                    length = admin.minimumPasswordSymbols;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.minimumPasswordSymbols) {
+                        length = admin.minimumPasswordSymbols;
+                    }
                 }
             }
             return length;
@@ -1823,12 +1937,16 @@
                 return admin != null ? admin.minimumPasswordNonLetter : length;
             }
 
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (length < admin.minimumPasswordNonLetter) {
-                    length = admin.minimumPasswordNonLetter;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (length < admin.minimumPasswordNonLetter) {
+                        length = admin.minimumPasswordNonLetter;
+                    }
                 }
             }
             return length;
@@ -1840,8 +1958,16 @@
             return true;
         }
         enforceCrossUserPermission(userHandle);
+
         synchronized (this) {
-            DevicePolicyData policy = getUserData(userHandle);
+
+            // The active password is stored in the user that runs the launcher
+            // If the user this is called from is part of a profile group, that is the parent
+            // of the group.
+            UserInfo parent = getProfileParent(userHandle);
+            int id = parent == null ? userHandle : parent.id;
+            DevicePolicyData policy = getUserData(id);
+
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(null,
@@ -1863,13 +1989,16 @@
     }
 
     public int getCurrentFailedPasswordAttempts(int userHandle) {
-        enforceCrossUserPermission(userHandle);
         synchronized (this) {
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(null,
                     DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
-            return getUserData(userHandle).mFailedPasswordAttempts;
+
+            // The active password is stored in the parent.
+            DevicePolicyData policy = getUserData(getProfileParent(userHandle).id);
+
+            return policy.mFailedPasswordAttempts;
         }
     }
 
@@ -1879,6 +2008,9 @@
         }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(who,
@@ -1898,7 +2030,6 @@
         }
         enforceCrossUserPermission(userHandle);
         synchronized (this) {
-            DevicePolicyData policy = getUserData(userHandle);
             int count = 0;
 
             if (who != null) {
@@ -1906,14 +2037,19 @@
                 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
             }
 
-            final int N = policy.mAdminList.size();
-            for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (count == 0) {
-                    count = admin.maximumFailedPasswordsForWipe;
-                } else if (admin.maximumFailedPasswordsForWipe != 0
-                        && count > admin.maximumFailedPasswordsForWipe) {
-                    count = admin.maximumFailedPasswordsForWipe;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (count == 0) {
+                        count = admin.maximumFailedPasswordsForWipe;
+                    } else if (admin.maximumFailedPasswordsForWipe != 0
+                            && count > admin.maximumFailedPasswordsForWipe) {
+                        count = admin.maximumFailedPasswordsForWipe;
+                    }
                 }
             }
             return count;
@@ -1925,9 +2061,11 @@
             return false;
         }
         enforceCrossUserPermission(userHandle);
+        enforceNotManagedProfile(userHandle, "reset the password");
+
         int quality;
         synchronized (this) {
-            // This API can only be called by an active device admin,
+            // This api can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(null,
                     DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
@@ -2105,15 +2243,19 @@
                 return admin != null ? admin.maximumTimeToUnlock : time;
             }
 
-            DevicePolicyData policy = getUserData(userHandle);
-            final int N = policy.mAdminList.size();
-            for  (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (time == 0) {
-                    time = admin.maximumTimeToUnlock;
-                } else if (admin.maximumTimeToUnlock != 0
-                        && time > admin.maximumTimeToUnlock) {
-                    time = admin.maximumTimeToUnlock;
+            // Return strictest policy for this user and profiles that are visible from this user.
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+                final int N = policy.mAdminList.size();
+                for (int i=0; i<N; i++) {
+                    ActiveAdmin admin = policy.mAdminList.get(i);
+                    if (time == 0) {
+                        time = admin.maximumTimeToUnlock;
+                    } else if (admin.maximumTimeToUnlock != 0
+                            && time > admin.maximumTimeToUnlock) {
+                        time = admin.maximumTimeToUnlock;
+                    }
                 }
             }
             return time;
@@ -2271,7 +2413,7 @@
                 public void run() {
                     try {
                         ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
-                        ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
+                        (mUserManager)
                                 .removeUser(userHandle);
                     } catch (RemoteException re) {
                         // Shouldn't happen
@@ -2319,6 +2461,8 @@
             return;
         }
         enforceCrossUserPermission(userHandle);
+        enforceNotManagedProfile(userHandle, "set the active password");
+
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
         DevicePolicyData p = getUserData(userHandle);
@@ -2347,7 +2491,8 @@
                     saveSettingsLocked(userHandle);
                     updatePasswordExpirationsLocked(userHandle);
                     setExpirationAlarmCheckLocked(mContext, p);
-                    sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
+                    sendAdminCommandToSelfAndProfilesLocked(
+                            DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
                             DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
                 } finally {
                     Binder.restoreCallingIdentity(ident);
@@ -2357,26 +2502,31 @@
     }
 
     /**
-     * Called any time the device password is updated.  Resets all password expiration clocks.
+     * Called any time the device password is updated. Resets all password expiration clocks.
      */
     private void updatePasswordExpirationsLocked(int userHandle) {
-        DevicePolicyData policy = getUserData(userHandle);
-        final int N = policy.mAdminList.size();
-        if (N > 0) {
-            for (int i=0; i<N; i++) {
-                ActiveAdmin admin = policy.mAdminList.get(i);
-                if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
-                    long timeout = admin.passwordExpirationTimeout;
-                    long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
-                    admin.passwordExpirationDate = expiration;
+            List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+            for (UserInfo userInfo : profiles) {
+                int profileId = userInfo.getUserHandle().getIdentifier();
+                DevicePolicyData policy = getUserData(profileId);
+                final int N = policy.mAdminList.size();
+                if (N > 0) {
+                    for (int i=0; i<N; i++) {
+                        ActiveAdmin admin = policy.mAdminList.get(i);
+                        if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
+                            long timeout = admin.passwordExpirationTimeout;
+                            long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
+                            admin.passwordExpirationDate = expiration;
+                        }
+                    }
                 }
+                saveSettingsLocked(profileId);
             }
-            saveSettingsLocked(userHandle);
-        }
     }
 
     public void reportFailedPasswordAttempt(int userHandle) {
         enforceCrossUserPermission(userHandle);
+        enforceNotManagedProfile(userHandle, "report failed password attempt");
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
 
@@ -2391,7 +2541,8 @@
                     if (max > 0 && policy.mFailedPasswordAttempts >= max) {
                         wipeDeviceOrUserLocked(0, userHandle);
                     }
-                    sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
+                    sendAdminCommandToSelfAndProfilesLocked(
+                            DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
                             DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
                 }
             } finally {
@@ -2414,7 +2565,8 @@
                     policy.mPasswordOwner = -1;
                     saveSettingsLocked(userHandle);
                     if (mHasFeature) {
-                        sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
+                        sendAdminCommandToSelfAndProfilesLocked(
+                                DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
                                 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
                     }
                 } finally {
@@ -2443,7 +2595,7 @@
             // Scan through active admins and find if anyone has already
             // set the global proxy.
             Set<ComponentName> compSet = policy.mAdminMap.keySet();
-            for  (ComponentName component : compSet) {
+            for (ComponentName component : compSet) {
                 ActiveAdmin ap = policy.mAdminMap.get(component);
                 if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
                     // Another admin already sets the global proxy
@@ -2472,8 +2624,11 @@
             // Reset the global proxy accordingly
             // Do this using system permissions, as apps cannot write to secure settings
             long origId = Binder.clearCallingIdentity();
-            resetGlobalProxyLocked(policy);
-            Binder.restoreCallingIdentity(origId);
+            try {
+                resetGlobalProxyLocked(policy);
+            } finally {
+                Binder.restoreCallingIdentity(origId);
+            }
             return null;
         }
     }
@@ -2533,7 +2688,7 @@
         exclusionList = exclusionList.trim();
         ContentResolver res = mContext.getContentResolver();
 
-        ProxyProperties proxyProperties = new ProxyProperties(data[0], proxyPort, exclusionList);
+        ProxyInfo proxyProperties = new ProxyInfo(data[0], proxyPort, exclusionList);
         if (!proxyProperties.isValid()) {
             Slog.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
             return;
@@ -2858,8 +3013,7 @@
         }
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
 
-        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        if (um.getUserInfo(userHandle) == null) {
+        if (mUserManager.getUserInfo(userHandle) == null) {
             // User doesn't exist.
             throw new IllegalArgumentException(
                     "Attempted to set profile owner for invalid userId: " + userHandle);
@@ -2905,10 +3059,9 @@
             int userId = UserHandle.getCallingUserId();
             Slog.d(LOG_TAG, "Enabling the profile for: " + userId);
 
-            UserManager um = UserManager.get(mContext);
             long id = Binder.clearCallingIdentity();
             try {
-                um.setUserEnabled(userId);
+                mUserManager.setUserEnabled(userId);
                 Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED);
                 intent.putExtra(Intent.EXTRA_USER, new UserHandle(UserHandle.getCallingUserId()));
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY |
@@ -2972,6 +3125,30 @@
         }
     }
 
+    private void enforceNotManagedProfile(int userHandle, String message) {
+        if(isManagedProfile(userHandle)) {
+            throw new SecurityException("You can not " + message + " from a managed profile. ");
+        }
+    }
+
+    private UserInfo getProfileParent(int userHandle) {
+        long ident = Binder.clearCallingIdentity();
+        try {
+            return mUserManager.getProfileParent(userHandle);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private boolean isManagedProfile(int userHandle) {
+        long ident = Binder.clearCallingIdentity();
+        try {
+            return mUserManager.getUserInfo(userHandle).isManagedProfile();
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
     private void enableIfNecessary(String packageName, int userId) {
         try {
             IPackageManager ipm = AppGlobals.getPackageManager();
@@ -3075,10 +3252,9 @@
             }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            UserManager um = UserManager.get(mContext);
             long id = Binder.clearCallingIdentity();
             try {
-                um.setApplicationRestrictions(packageName, settings, userHandle);
+                mUserManager.setApplicationRestrictions(packageName, settings, userHandle);
             } finally {
                 restoreCallingIdentity(id);
             }
@@ -3142,10 +3318,9 @@
             }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            UserManager um = UserManager.get(mContext);
             long id = Binder.clearCallingIdentity();
             try {
-                return um.getApplicationRestrictions(packageName, userHandle);
+                return mUserManager.getApplicationRestrictions(packageName, userHandle);
             } finally {
                 restoreCallingIdentity(id);
             }
@@ -3162,10 +3337,9 @@
             }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            UserManager um = UserManager.get(mContext);
             long id = Binder.clearCallingIdentity();
             try {
-                um.setUserRestriction(key, enabled, userHandle);
+                mUserManager.setUserRestriction(key, enabled, userHandle);
             } finally {
                 restoreCallingIdentity(id);
             }
@@ -3178,7 +3352,6 @@
             if (who == null) {
                 throw new NullPointerException("ComponentName is null");
             }
-
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             int userId = UserHandle.getCallingUserId();
@@ -3277,4 +3450,112 @@
         ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0, userId);
         return (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) > 0;
     }
+
+    @Override
+    public void setAccountManagementDisabled(ComponentName who, String accountType,
+            boolean disabled) {
+        if (!mHasFeature) {
+            return;
+        }
+        synchronized (this) {
+            if (who == null) {
+                throw new NullPointerException("ComponentName is null");
+            }
+            ActiveAdmin ap = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            if (disabled) {
+                ap.accountTypesWithManagementDisabled.add(accountType);
+            } else {
+                ap.accountTypesWithManagementDisabled.remove(accountType);
+            }
+            saveSettingsLocked(UserHandle.getCallingUserId());
+        }
+    }
+
+    @Override
+    public String[] getAccountTypesWithManagementDisabled() {
+        if (!mHasFeature) {
+            return null;
+        }
+        synchronized (this) {
+            DevicePolicyData policy = getUserData(UserHandle.getCallingUserId());
+            final int N = policy.mAdminList.size();
+            HashSet<String> resultSet = new HashSet<String>();
+            for (int i = 0; i < N; i++) {
+                ActiveAdmin admin = policy.mAdminList.get(i);
+                resultSet.addAll(admin.accountTypesWithManagementDisabled);
+            }
+            return resultSet.toArray(new String[resultSet.size()]);
+        }
+    }
+
+    /**
+     * Sets which componets may enter lock task mode.
+     *
+     * This function can only be called by the device owner or the profile owner.
+     * @param components The list of components allowed to enter lock task mode.
+     */
+    public void setLockTaskComponents(ComponentName[] components) throws SecurityException {
+        // Get the package names of the caller.
+        int uid = Binder.getCallingUid();
+        String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
+
+        // Check whether any of the package name is the device owner or the profile owner.
+        for (int i=0; i<packageNames.length; i++) {
+            String packageName = packageNames[i];
+            int userHandle = UserHandle.getUserId(uid);
+            String profileOwnerPackage = getProfileOwner(userHandle);
+            if (isDeviceOwner(packageName) ||
+                (profileOwnerPackage != null && profileOwnerPackage.equals(packageName))) {
+
+                // If a package name is the device owner or the profile owner,
+                // we update the component list.
+                DevicePolicyData policy = getUserData(userHandle);
+                policy.mLockTaskComponents.clear();
+                if (components != null) {
+                    for (int j=0; j<components.length; j++) {
+                        ComponentName component = components[j];
+                        policy.mLockTaskComponents.add(component);
+                    }
+                }
+
+                // Store the settings persistently.
+                saveSettingsLocked(userHandle);
+                return;
+            }
+        }
+        throw new SecurityException();
+    }
+
+    /**
+     * This function returns the list of components allowed to start the task lock mode.
+     */
+    public ComponentName[] getLockTaskComponents() {
+        int userHandle = UserHandle.USER_OWNER;
+        DevicePolicyData policy = getUserData(userHandle);
+        ComponentName[] tempArray = policy.mLockTaskComponents.toArray(new ComponentName[0]);
+        return tempArray;
+    }
+
+    /**
+     * This function lets the caller know whether the given component is allowed to start the
+     * lock task mode.
+     * @param component The component to check
+     */
+    public boolean isLockTaskPermitted(ComponentName component) {
+        // Get current user's devicepolicy
+        int uid = Binder.getCallingUid();
+        int userHandle = UserHandle.getUserId(uid);
+        DevicePolicyData policy = getUserData(userHandle);
+        for (int i=0; i<policy.mLockTaskComponents.size(); i++) {
+            ComponentName lockTaskComponent = policy.mLockTaskComponents.get(i);
+
+            // If the given component equals one of the component stored our device-owner-set
+            // list, we allow this component to start the lock task mode.
+            if (lockTaskComponent.getPackageName().equals(component.getPackageName())) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7c9f7a8..22e2a6e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -73,6 +73,7 @@
 import com.android.server.net.NetworkStatsService;
 import com.android.server.notification.NotificationManagerService;
 import com.android.server.os.SchedulingPolicyService;
+import com.android.server.pm.BackgroundDexOptService;
 import com.android.server.pm.Installer;
 import com.android.server.pm.LauncherAppsService;
 import com.android.server.pm.PackageManagerService;
@@ -333,6 +334,7 @@
         InputManagerService inputManager = null;
         TelephonyRegistry telephonyRegistry = null;
         ConsumerIrService consumerIr = null;
+        AudioService audioService = null;
 
         boolean onlyCore = false;
         boolean firstBoot = false;
@@ -604,6 +606,14 @@
 
             if (!disableNetwork) {
                 try {
+                    Slog.i(TAG, "Network Score Service");
+                    networkScore = new NetworkScoreService(context);
+                    ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
+                } catch (Throwable e) {
+                    reportWtf("starting Network Score Service", e);
+                }
+
+                try {
                     Slog.i(TAG, "NetworkStats Service");
                     networkStats = new NetworkStatsService(context, networkManagement, alarm);
                     ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
@@ -641,6 +651,15 @@
                 }
 
                 try {
+                    Slog.i(TAG, "Wi-Fi Scanning Service");
+                    mSystemServiceManager.startService(
+                            "com.android.server.wifi.WifiScanningService");
+
+                } catch (Throwable e) {
+                    reportWtf("starting Wi-Fi Scanning Service", e);
+                }
+
+                try {
                     Slog.i(TAG, "Connectivity Service");
                     connectivity = new ConnectivityService(
                             context, networkManagement, networkStats, networkPolicy);
@@ -652,14 +671,6 @@
                 }
 
                 try {
-                    Slog.i(TAG, "Network Score Service");
-                    networkScore = new NetworkScoreService(context);
-                    ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
-                } catch (Throwable e) {
-                    reportWtf("starting Network Score Service", e);
-                }
-
-                try {
                     Slog.i(TAG, "Network Service Discovery Service");
                     serviceDiscovery = NsdService.create(context);
                     ServiceManager.addService(
@@ -759,7 +770,8 @@
             if (!disableMedia && !"0".equals(SystemProperties.get("system_init.startaudioservice"))) {
                 try {
                     Slog.i(TAG, "Audio Service");
-                    ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context));
+                    audioService = new AudioService(context);
+                    ServiceManager.addService(Context.AUDIO_SERVICE, audioService);
                 } catch (Throwable e) {
                     reportWtf("starting Audio Service", e);
                 }
@@ -962,6 +974,13 @@
                 } catch (Throwable e) {
                     Slog.e(TAG, "Failure starting TrustManagerService", e);
                 }
+
+                try {
+                    Slog.i(TAG, "BackgroundDexOptService");
+                    new BackgroundDexOptService(context);
+                } catch (Throwable e) {
+                    reportWtf("starting BackgroundDexOptService", e);
+                }
             }
 
             try {
@@ -1067,6 +1086,7 @@
         final InputManagerService inputManagerF = inputManager;
         final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
         final MediaRouterService mediaRouterF = mediaRouter;
+        final AudioService audioServiceF = audioService;
 
         // We now tell the activity manager it is okay to run third party
         // code.  It will call back into us once it has gotten to the state
@@ -1135,6 +1155,11 @@
                 } catch (Throwable e) {
                     reportWtf("making Recognition Service ready", e);
                 }
+                try {
+                    if (audioServiceF != null) audioServiceF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("Notifying AudioService running", e);
+                }
                 Watchdog.getInstance().start();
 
                 // It is now okay to let the various system services start their
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index af0d0ad..3e9cf43 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -232,6 +232,15 @@
                 <category android:name="com.android.test.hwui.TEST" />
             </intent-filter>
         </activity>
+
+        <activity
+                android:name="LooperAcceleration"
+                android:label="Misc/LooperAcceleration">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.hwui.TEST" />
+            </intent-filter>
+        </activity>
         
         <activity
                 android:name="TextFadeActivity"
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java b/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java
new file mode 100644
index 0000000..20d8e11
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/LooperAcceleration.java
@@ -0,0 +1,96 @@
+/*
+ * 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.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.Canvas;
+import android.os.Bundle;
+import android.os.Looper;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.LinearLayout;
+
+public class LooperAcceleration extends Activity {
+
+    static final boolean INCLUDE_WEBVIEW = false;
+
+    static class IsAcceleratedView extends View {
+
+        public IsAcceleratedView(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            if (canvas.isHardwareAccelerated()) {
+                canvas.drawARGB(0xFF, 0x00, 0xFF, 0x00);
+            } else {
+                canvas.drawARGB(0xFF, 0xFF, 0x00, 0x00);
+            }
+        }
+
+    }
+
+    private View makeView() {
+        LinearLayout layout = new LinearLayout(this);
+        layout.addView(new IsAcceleratedView(this), LayoutParams.MATCH_PARENT, 60);
+
+        if (INCLUDE_WEBVIEW) {
+            WebView wv = new WebView(this);
+            wv.setWebViewClient(new WebViewClient());
+            wv.setWebChromeClient(new WebChromeClient());
+            wv.loadUrl("http://www.webkit.org/blog-files/3d-transforms/poster-circle.html");
+            layout.addView(wv, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+        }
+        return layout;
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(makeView());
+
+        new Thread() {
+            @Override
+            public void run() {
+                Looper.prepare();
+                final Context context = LooperAcceleration.this;
+                Dialog dlg = new Dialog(context);
+                dlg.addContentView(makeView(), new LayoutParams(300, 400));
+                dlg.setCancelable(true);
+                dlg.setCanceledOnTouchOutside(true);
+                dlg.setOnDismissListener(new DialogInterface.OnDismissListener() {
+                    @Override
+                    public void onDismiss(DialogInterface dialog) {
+                        Looper.myLooper().quit();
+                    }
+                });
+                dlg.setTitle("Not Looper.getMainLooper() check");
+                dlg.show();
+                Looper.loop();
+            }
+        }.start();
+    }
+}
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
index bb2bebf..d0f2a2d 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable01.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:trigger="state_checked" android:versionCode="1" >
+    android:versionCode="1" >
 
     <size
         android:height="48dp"
@@ -26,53 +26,11 @@
 
     <group>
         <path
-            android:name="check"
-            android:pathData="m20,200l100,90l180,-180l-35,-35l-145,145l-60,-60l-40,40z"
-            android:fill="?android:attr/colorControlActivated" />
-    </group>
-    <group>
-        <path
             android:name="box1"
-            android:pathData="m127,171l37,38l33,-31l-37,-40l-1,3l-2,0l-30,30z"
+            android:pathData="m20,200l100,90l180,-180l-35,-35l-145,145l-60,-60l-40,40z"
             android:fill="?android:attr/colorControlActivated"
             android:stroke="?android:attr/colorControlActivated"
             android:strokeLineCap="round"
             android:strokeLineJoin="round" />
     </group>
-    <group>
-        <path
-            android:name="box2"
-            android:pathData="m127,171l37,38l33,-31l-37,-40l-1,3l-2,0l-30,30z"
-            android:rotation="46.757"
-            android:pivotX="162"
-            android:pivotY="173.5"
-            android:fill="?android:attr/colorControlNormal"
-            android:stroke="?android:attr/colorControlNormal"
-            android:strokeWidth="3"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
-    <group>
-        <path
-            android:name="box3"
-            android:pathData="m187,147l-1,55l-49,-1l2,-53l48,0z"
-            android:stroke="?android:attr/colorControlNormal"
-            android:strokeWidth="10"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
-    <group>
-        <path
-            android:name="box4"
-            android:pathData="m248,74l0,164l-177,0l1,-165l173,-1l3,2z"
-            android:stroke="?android:attr/colorControlNormal"
-            android:strokeWidth="30"
-            android:strokeLineCap="round"
-            android:strokeLineJoin="round" />
-    </group>
-
-    <animation
-        android:durations="300,100,0,300"
-        android:sequence="check,box1,box2,box3,box4" />
-
 </vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
index 49906d17..728624a 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable02.xml
@@ -23,14 +23,6 @@
 
     <group>
         <path
-                android:name="arrow"
-                android:pathData="M 100,225 L 100,115 L 130,115 L 70,15 L 10,115 L 40,115 L 40,225 z"
-                android:fill="#ffffffff"
-                android:stroke="#FF00FF00"
-                android:strokeWidth="1"/>
-    </group>
-    <group>
-        <path
                 android:name="house"
                 android:pathData="M 130,225 L 130,115 L 130,115 L 70,15 L 10,115 L 10,115 L 10,225 z"
                 android:fill="#ff440000"
@@ -42,5 +34,4 @@
                 android:trimPathStart=".1"
                 android:trimPathEnd=".9"/>
     </group>
-    <animation android:sequence="arrow,house"/>
 </vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
index 137049d..1792683 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable03.xml
@@ -71,67 +71,4 @@
                 android:fill="#ff88ff"
                 />
     </group>
-    <group>
-        <path
-                android:name="clip1"
-                android:pathData="
-                M 0, 0
-                l 7.3, 0
-                l 0, 12.25
-                l -7.3, 0
-                z"
-                android:clipToPath="true"
-                android:rotation="-30"
-                android:pivotX="3.65"
-                android:pivotY="6.125"
-                />
-        <path
-                android:name="one"
-                android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
-                l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
-                l -5.046875,0.0 0.0,-1.0Z"
-                android:fill="#ff88ff"
-                />
-        <path
-                android:name="clip2"
-                android:pathData="
-                M 0, 12.25
-                l 7.3, 0
-                l 0, 12.25
-                l -7.3, 0
-                z"
-                android:clipToPath="true"
-                android:rotation="-30"
-                android:pivotX="3.65"
-                android:pivotY="6.125"
-                />
-        <path
-                android:name="two"
-                android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
-                        q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
-                        q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
-                        q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
-                        q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
-                        q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
-                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
-                        q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z"
-                android:fill="#ff88ff"
-                />
-    </group>
-
-
-    <animation
-            android:sequence="one,one"
-            android:durations="4000"/>
-    <animation
-            android:sequence="two,two"
-            android:durations="4000"/>
-    <animation
-            android:sequence="clip1,clip1"
-            android:durations="4000"/>
-    <animation
-            android:sequence="clip2,clip2"
-            android:durations="4000"/>
-
 </vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
index cffb73f..90694fb 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml
@@ -65,62 +65,4 @@
                 android:fill="#ff88ff"
                 />
     </group>
-    <group>
-        <path
-                android:name="clip1"
-                android:pathData="
-                M 3.65, 6.125
-                m -6, 0
-                a 6,6 0 1,0 12,0
-                a 6,6 0 1,0 -12,0z"
-                android:clipToPath="true"
-                android:fill="#332233"
-                />
-        <path
-                android:name="one"
-                android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
-                l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
-                l -5.046875,0.0 0.0,-1.0Z"
-                android:fill="#ff88ff"
-                />
-        <path
-                android:name="clip2"
-                android:pathData="
-                 M 3.65, 6.125
-                m -.001, 0
-                a .001,.001 0 1,0 .002,0
-                a .001,.001 0 1,0 -.002,0z"
-                android:clipToPath="true"
-                android:fill="#662233"
-                />
-        <path
-                android:name="two"
-                android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
-                        q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
-                        q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
-                        q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
-                        q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
-                        q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
-                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
-                        q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z"
-                android:fill="#ff88ff"
-                />
-    </group>
-
-
-
-    <animation
-            android:sequence="one,one"
-            android:durations="4000"/>
-    <animation
-            android:sequence="two,two"
-            android:durations="4000"/>
-    <animation
-            android:sequence="clip1,clip1"
-            android:durations="4000"/>
-    <animation
-            android:sequence="clip2,clip2"
-            android:durations="4000"/>
-
 </vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
index 0be6755..c6595fa 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable05.xml
@@ -44,95 +44,4 @@
                         q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
                         q -0.78125024,0.8125 -2.2187502,2.265625Z" />
     </group>
-    <group>
-        <path
-            android:name="one"
-            android:fill="#ffff00"
-            android:fillOpacity="0"
-            android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0,-6.671875 -2.109375,0.421875 0.0,-1.078125
-l 2.09375,-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0
-l -5.046875,0.0 0.0,-1.0Z" />
-        <path
-            android:name="two"
-            android:fill="#ffff00"
-            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
-                        q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
-                        q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
-                        q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
-                        q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
-                        q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
-                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
-                        q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z" />
-    </group>
-    <group>
-        <path
-            android:name="two"
-            android:fill="#ffff00"
-            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
-                        q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
-                        q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
-                        q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
-                        q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
-                        q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
-                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
-                        q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z" />
-        <path
-            android:name="three"
-            android:fill="#ffff00"
-            android:fillOpacity="0"
-            android:pathData="M 5.103125,6.003125q 0.84375,0.1875 1.3125,0.765625 0.484375,0.5625 0.484375,1.40625
-                        q 0.0,1.296875 -0.890625,2.015625 -0.890625,0.703125 -2.53125,0.703125
-                        q -0.546875,0.0 -1.140625,-0.109375 -0.5781251,-0.109375 -1.1875001,-0.328125
-                        l 0.0,-1.140625q 0.484375,0.28125 1.0625001,0.4375 0.59375,0.140625 1.234375,0.140625
-                        q 1.109375,0.0 1.6875,-0.4375 0.59375,-0.4375 0.59375,-1.28125
-                        q 0.0,-0.765625 -0.546875,-1.203125 -0.546875,-0.4375 -1.5,-0.4375
-                        l -1.03125,0.0 0.0,-0.96875 1.078125,0.0q 0.859375,0.0 1.328125,-0.34375
-                        q 0.46875,-0.359375 0.46875,-1.015625 0.0,-0.671875 -0.484375,-1.03125
-                        q -0.46875,-0.359375 -1.359375,-0.359375 -0.5,0.0 -1.0625,0.109375
-                        q -0.546875,0.09375 -1.2187501,0.3125l 0.0,-1.046875q 0.6875001,-0.1875 1.2656251,-0.28125
-                        q 0.59375,-0.09375 1.109375,-0.09375 1.359375,0.0 2.140625,0.609375
-                        q 0.78125,0.609375 0.78125,1.65625 0.0,0.734375 -0.421875,1.234375
-                        q -0.40625,0.5 -1.171875,0.6875Z" />
-    </group>
-    <group>
-        <path
-            android:name="two"
-            android:fill="#ffff00"
-            android:fillOpacity="0"
-            android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0 -5.5625,0.0 0.0,-1.0q 0.671875,-0.6875 1.828125,-1.859375
-                        q 1.1718752,-1.1875 1.4687502,-1.53125 0.578125,-0.625 0.796875,-1.0625
-                        q 0.234375,-0.453125 0.234375,-0.875 0.0,-0.703125 -0.5,-1.140625
-                        q -0.484375,-0.4375 -1.2656252,-0.4375 -0.5625,0.0 -1.1875,0.1875
-                        q -0.609375,0.1875 -1.3125,0.59375l 0.0,-1.203125q 0.71875,-0.28125 1.328125,-0.421875
-                        q 0.625,-0.15625 1.140625,-0.15625 1.3593752,0.0 2.1718752,0.6875
-                        q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125 -0.203125,1.015625
-                        q -0.203125,0.484375 -0.734375,1.140625 -0.15625,0.171875 -0.9375,0.984375
-                        q -0.78125024,0.8125 -2.2187502,2.265625Z" />
-        <path
-            android:name="three"
-            android:fill="#ffff00"
-            android:pathData="M 5.103125,6.003125q 0.84375,0.1875 1.3125,0.765625 0.484375,0.5625 0.484375,1.40625
-                        q 0.0,1.296875 -0.890625,2.015625 -0.890625,0.703125 -2.53125,0.703125
-                        q -0.546875,0.0 -1.140625,-0.109375 -0.5781251,-0.109375 -1.1875001,-0.328125
-                        l 0.0,-1.140625q 0.484375,0.28125 1.0625001,0.4375 0.59375,0.140625 1.234375,0.140625
-                        q 1.109375,0.0 1.6875,-0.4375 0.59375,-0.4375 0.59375,-1.28125
-                        q 0.0,-0.765625 -0.546875,-1.203125 -0.546875,-0.4375 -1.5,-0.4375
-                        l -1.03125,0.0 0.0,-0.96875 1.078125,0.0q 0.859375,0.0 1.328125,-0.34375
-                        q 0.46875,-0.359375 0.46875,-1.015625 0.0,-0.671875 -0.484375,-1.03125
-                        q -0.46875,-0.359375 -1.359375,-0.359375 -0.5,0.0 -1.0625,0.109375
-                        q -0.546875,0.09375 -1.2187501,0.3125l 0.0,-1.046875q 0.6875001,-0.1875 1.2656251,-0.28125
-                        q 0.59375,-0.09375 1.109375,-0.09375 1.359375,0.0 2.140625,0.609375
-                        q 0.78125,0.609375 0.78125,1.65625 0.0,0.734375 -0.421875,1.234375
-                        q -0.40625,0.5 -1.171875,0.6875Z" />
-    </group>
-
-    <animation
-        android:durations="2000,0,2000"
-        android:sequence="one,one,three,three" />
-    <animation
-        android:durations="2000,0,2000"
-        android:sequence="two,two,two,two" />
-
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
index 73ff5e2..850de28 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable06.xml
@@ -23,29 +23,6 @@
             android:viewportHeight="700"/>
 
     <group>
-    </group>
-    <path android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
-          android:name="path2451"
-          android:stroke="#FF000000"
-          android:strokeWidth="30.65500000000000"/>
-    <path android:pathData="M 365.015 311.066"
-          android:name="path2453"
-          android:stroke="#FF000000"
-          android:strokeWidth="30.655000000000001"/>
-    <path android:pathData="M 164.46 164.49L 340.78 343.158C 353.849 356.328 377.63 356.172 390.423 343.278L 566.622 165.928"
-          android:name="path2455"
-          android:stroke="#FF000000"
-          android:fill="#FF0000FF"
-          android:strokeWidth="30.655000000000001"/>
-    <path android:pathData="M 170.515 451.566L 305.61 313.46"
-          android:name="path2457"
-          android:stroke="#000000"
-          android:strokeWidth="30.655000000000001"/>
-    <path android:pathData="M 557.968 449.974L 426.515 315.375"
-          android:name="path2459"
-          android:stroke="#000000"
-          android:strokeWidth="30.655000000000001"/>
-    <group>
         <path android:pathData="M 569.374 461.472L 569.374 160.658L 160.658 160.658L 160.658 461.472L 569.374 461.472z"
               android:name="path2451"
               android:stroke="#FF000000"
@@ -68,9 +45,4 @@
               android:stroke="#000000"
               android:strokeWidth="30.655000000000001"/>
     </group>
-
-    <animation android:sequence="path2451,path2451"
-        android:durations="1000"/>
-
-
 </vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
index 99d37ef..7c7e679 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable07.xml
@@ -19,14 +19,7 @@
 
     <viewport android:viewportWidth="140"
           android:viewportHeight="110"/>
-    <group>
-        <path
-                android:name="menu"
-                android:pathData="M 20,20 l 100,0 0,10 -100,0 z
-              M 20,50 l 100,0 0,10 -100,0 z
-              M 20,80 l 0,-10 100,0 0,10 z"
-                android:fill="#ffffffff"/>
-    </group>
+
     <group>
         <path
                 android:name="back"
@@ -34,12 +27,6 @@
               M 27,50 l 97,0 0,10 -97,0 z
               M 20,55 l 7.07,-7.07 35.3,35.3 -7.07,7.07 z"
                 android:fill="#ffffffff"
-                android:rotation="180"
-                android:pivotX="70"
-                android:pivotY="55"
                 />
     </group>
-    <animation android:sequence="menu,back"/>
-
-
 </vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
index f8a03d7..59f7459 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable08.xml
@@ -31,18 +31,4 @@
                 android:strokeWidth="1"/>
     </group>
 
-    <group>
-        <path
-                android:name="pie2"
-                android:pathData="M564.441,287A280.868,280.868 0 1,1 564.441,285L284.493,286.29Z"
-                android:fill="#FFccaa00"
-                android:stroke="#FF000000"
-                android:strokeWidth="10"
-                android:pivotX="90"
-                android:pivotY="100"/>
-    </group>
-
-    <animation android:sequence="pie1,pie2"/>
-
-
 </vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
index b3c91a88..2e379d6 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable09.xml
@@ -25,12 +25,6 @@
 
     <group>
         <path
-            android:name="arrow"
-            android:fill="#ffffffff"
-            android:pathData="M 20,20 l 60,0 0,140 -60,0 z M 120,20 l 60,0 0,140 -60,0 z" />
-    </group>
-    <group>
-        <path
             android:name="house"
             android:fill="#ffffffff"
             android:pathData="M 100,20 l 0,0 0,140 -80,0 z M 100,20 l 0,0 80,140 -80,0 z"
@@ -39,6 +33,4 @@
             android:rotation="90" />
     </group>
 
-    <animation android:sequence="arrow,house" />
-
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
index 7aca169..8484e9e 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable10.xml
@@ -21,8 +21,8 @@
         android:width="64dp" />
 
     <viewport
-        android:viewportHeight="200"
-        android:viewportWidth="200" />
+        android:viewportWidth="200"
+        android:viewportHeight="200"/>
 
     <group>
         <path
@@ -31,24 +31,6 @@
             android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
         <path
             android:name="bar2"
-            android:fill="#FF555555"
-            android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
-        <path
-            android:name="bar1"
-            android:fill="#FF555555"
-            android:pathData="M14.001,34.645   L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
-        <path
-            android:name="bar0"
-            android:fill="#FF555555"
-            android:pathData="M0,20.502l6.999,7.071   c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
-    </group>
-    <group>
-        <path
-            android:name="bar3"
-            android:fill="#FFFFFFFF"
-            android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
-        <path
-            android:name="bar2"
             android:fill="#FFFFFFFF"
             android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
         <path
@@ -60,54 +42,5 @@
             android:fill="#FF555555"
             android:pathData="M0,20.502l6.999,7.071   c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
     </group>
-    <group>
-        <path
-            android:name="bar3"
-            android:fill="#FFFFFFFF"
-            android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
-        <path
-            android:name="bar2"
-            android:fill="#FFFFFFFF"
-            android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
-        <path
-            android:name="bar1"
-            android:fill="#FFFFFFFF"
-            android:pathData="M14.001,34.645   L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
-        <path
-            android:name="bar0"
-            android:fill="#FF555555"
-            android:pathData="M0,20.502l6.999,7.071   c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
-    </group>
-    <group>
-        <path
-            android:name="bar3"
-            android:fill="#FFFFFFFF"
-            android:pathData="M49.001,60c-5.466,0 -9.899,4.478 -9.899,10s4.434,10,9.899,10c5.468,0,9.899 -4.478,9.899 -10S54.469,60,49.001,60z" />
-        <path
-            android:name="bar2"
-            android:fill="#FFFFFFFF"
-            android:pathData="M28.001,48.787l7,7.07c7.731 -7.811,20.269 -7.81,28.001,0l6.999 -7.07C58.403,37.071,39.599,37.071,28.001,48.787z" />
-        <path
-            android:name="bar1"
-            android:fill="#FFFFFFFF"
-            android:pathData="M14.001,34.645   L21,41.716c15.464 -15.621,40.536 -15.621,56,0l7.001 -7.071C64.672,15.119,33.33,15.119,14.001,34.645z" />
-        <path
-            android:name="bar0"
-            android:fill="#FFFFFFFF"
-            android:pathData="M0,20.502l6.999,7.071   c23.196 -23.431,60.806 -23.431,84.002,0L98,20.503C70.938 -6.834,27.063 -6.834,0,20.502z" />
-    </group>
-
-    <animation
-        android:durations="500,500,500"
-        android:sequence="bar0,bar0,bar0,bar0" />
-    <animation
-        android:durations="500,500,500"
-        android:sequence="bar1,bar1,bar1,bar1" />
-    <animation
-        android:durations="500,500,500"
-        android:sequence="bar2,bar2,bar2,bar2" />
-    <animation
-        android:durations="500,500,500"
-        android:sequence="bar3,bar3,bar3,bar3" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
index a4403c5..2b6c5d3 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable11.xml
@@ -36,25 +36,5 @@
             android:fill="#FFFF0000"
             android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
     </group>
-    <group>
-        <path
-            android:name="battery"
-            android:fill="#ff8833"
-            android:pathData="M 20.28125,2.0000002 C 17.352748,2.0000002 15,4.3527485 15,7.2812502 L 15,8.0000002 L 13.15625,8.0000002 C 9.7507553,8.0000002 7,10.750759 7,14.15625 L 7,39.84375 C 7,43.24924 9.7507558,46 13.15625,46 L 33.84375,46 C 37.249245,46 39.999999,43.24924 40,39.84375 L 40,14.15625 C 40,10.75076 37.249243,8.0000002 33.84375,8.0000002 L 32,8.0000002 L 32,7.2812502 C 32,4.3527485 29.647252,2.0000002 26.71875,2.0000002 L 20.28125,2.0000002 z"
-            android:rotation="0"
-            android:stroke="#3388ff"
-            android:strokeWidth="1" />
-        <path
-            android:name="spark"
-            android:fill="#FFFF0000"
-            android:pathData="M 30,18.031528 L 25.579581,23.421071 L 29.370621,26.765348 L 20.096792,37 L 21.156922,28.014053 L 17,24.902844 L 20.880632,18 L 30,18.031528 z" />
-    </group>
-
-    <animation
-        android:durations="2000"
-        android:sequence="spark,spark" />
-    <animation
-        android:durations="2000"
-        android:sequence="battery,battery" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
index 207879d..681eb4f 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable12.xml
@@ -40,48 +40,5 @@
             android:pivotY="300"
             android:rotation="0" />
     </group>
-    <group>
-        <path
-            android:name="v"
-            android:pathData="M300,70 l 0,-70 70,70 -70,70z"
-            android:pivotX="300"
-            android:pivotY="300"
-            android:rotation="360" />
-        <path
-            android:name="pie2"
-            android:pathData="M300,70 a230,230 0 1,0 1,0 z"
-            android:pivotX="300"
-            android:pivotY="300"
-            android:rotation="360"
-            android:stroke="#FF00FF00"
-            android:strokeLineCap="round"
-            android:strokeWidth="70"
-            android:trimPathEnd=".5"
-            android:trimPathOffset="0"
-            android:trimPathStart="0" />
-    </group>
-
-    <animation
-        android:animate="easeInOut"
-        android:durations="2000"
-        android:repeatCount="-1"
-        android:repeatStyle="forward"
-        android:sequence="pie1,pie2"
-        android:startOffset="500" />
-    <animation
-        android:animate="easeInOut"
-        android:durations="2000"
-        android:repeatCount="-1"
-        android:repeatStyle="forward"
-        android:sequence="v,v"
-        android:startOffset="500" />
-    <animation
-        android:animate="easeInOut"
-        android:durations="2800"
-        android:limitTo="trimPathEnd"
-        android:repeatCount="-1"
-        android:repeatStyle="reverse"
-        android:sequence="pie1,pie2"
-        android:startOffset="500" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
index 4a2ed90..ef1b8e4 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable13.xml
@@ -40,40 +40,5 @@
             android:stroke="#FF0000FF"
             android:strokeWidth="5" />
     </group>
-    <group>
-        <path
-            android:name="pie2"
-            android:fill="#ffff0000"
-            android:pathData="M300,200 h-150 a150,150 0 1,0 150,-150 z"
-            android:pivotX="300"
-            android:pivotY="200"
-            android:rotation="360"
-            android:stroke="#FF00FF00"
-            android:strokeWidth="10" />
-        <path
-            android:name="half"
-            android:fill="#FFFFFF00"
-            android:pathData="M275,175 v-150 a150,150 0 0,0 -150,150 z"
-            android:pivotX="300"
-            android:pivotY="200"
-            android:rotation="-360"
-            android:stroke="#FF0000FF"
-            android:strokeWidth="5" />
-    </group>
-
-    <animation
-        android:animate="easeInOut"
-        android:durations="1000"
-        android:repeatCount="2"
-        android:repeatStyle="forward"
-        android:sequence="pie1,pie2"
-        android:startOffset="500" />
-    <animation
-        android:animate="easeInOut"
-        android:durations="1000"
-        android:repeatCount="5"
-        android:repeatStyle="forward"
-        android:sequence="half,half"
-        android:startOffset="500" />
 
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
index 6ebd56b..77bf723 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable14.xml
@@ -25,17 +25,6 @@
 
     <group>
         <path
-            android:name="pie1"
-            android:pathData="M200,450 l 50,-25
-           a25,25 -30 0,1 100,-50 l 50,-25
-           a25,50 -30 0,1 100,-50 l 50,-25
-           a25,75 -30 0,1 100,-50 l 50,-25
-           a25,100 -30 0,1 100,-50 l 50,-25"
-            android:stroke="#FF00FF00"
-            android:strokeWidth="10" />
-    </group>
-    <group>
-        <path
             android:name="pie2"
             android:pathData="M200,350 l 50,-25
            a25,12 -30 0,1 100,-50 l 50,-25
@@ -49,6 +38,4 @@
             android:strokeWidth="10" />
     </group>
 
-    <animation android:sequence="pie1,pie2" />
-
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
index 3c92d25..df5838c 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable15.xml
@@ -25,14 +25,6 @@
 
     <group>
         <path
-            android:name="arrow"
-            android:fill="#ffffffff"
-            android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
-            android:stroke="#FFFF0000"
-            android:strokeWidth="1" />
-    </group>
-    <group>
-        <path
             android:name="house"
             android:fill="#ff440000"
             android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
@@ -43,6 +35,4 @@
             android:strokeWidth="10" />
     </group>
 
-    <animation android:sequence="arrow,house" />
-
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
index 7e757a5..0bdcda5 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable16.xml
@@ -25,13 +25,6 @@
 
     <group>
         <path
-            android:name="arrow"
-            android:pathData="M 100,10 v 180 M 10,100 h 180"
-            android:stroke="#FF00FF00"
-            android:strokeWidth="1" />
-    </group>
-    <group>
-        <path
             android:name="house"
             android:pathData="M 100,10 v 90 M 10,100 h 90"
             android:pivotX="100"
@@ -41,6 +34,4 @@
             android:strokeWidth="10" />
     </group>
 
-    <animation android:sequence="arrow,house" />
-
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
index 9427652..4453ae4 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable17.xml
@@ -23,14 +23,6 @@
 
     <group>
         <path
-                android:name="arrow"
-                android:pathData="M200,300 Q400,50 600,300 T1000,300"
-                android:stroke="#FF00FF00"
-                android:strokeWidth="1"/>
-    </group>
-
-    <group>
-        <path
                 android:name="house"
                 android:pathData="M200,300 Q400,50 600,300 T1000,300"
                 android:stroke="#FFFF0000"
@@ -40,7 +32,4 @@
                 android:pivotY="300"/>
     </group>
 
-    <animation android:sequence="arrow,house"/>
-
-
 </vector>
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
index 69212f5..dfae9ac 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable18.xml
@@ -25,21 +25,13 @@
 
     <group>
         <path
-            android:name="arrow"
-            android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
-            android:stroke="#FFFFFF00"
-            android:strokeWidth="10" />
-    </group>
-    <group>
-        <path
             android:name="house"
             android:pathData="M100,200 C100,100 250,100 250,200 S400,300 400,200"
             android:pivotX="250"
             android:pivotY="200"
             android:rotation="360"
+            android:stroke="#FFFFFF00"
             android:strokeWidth="10" />
     </group>
 
-    <animation android:sequence="arrow,house" />
-
 </vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
index 2dca48d..a890fd6 100644
--- a/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable19.xml
@@ -25,13 +25,6 @@
 
     <group>
         <path
-            android:name="arrow"
-            android:pathData="M10,300 Q400,50 600,300 T1000,300"
-            android:stroke="#FF00FFFF"
-            android:strokeWidth="40" />
-    </group>
-    <group>
-        <path
             android:name="house"
             android:pathData="M10,300 Q400,550 600,300 T1000,300"
             android:pivotX="90"
@@ -40,6 +33,4 @@
             android:strokeWidth="60" />
     </group>
 
-    <animation android:sequence="arrow,house" />
-
 </vector>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index bb05d45..aede236 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -71,7 +71,7 @@
      * Returns the native delegate associated to a given {@link Canvas} object.
      */
     public static Canvas_Delegate getDelegate(Canvas canvas) {
-        return sManager.getDelegate(canvas.mNativeCanvas);
+        return sManager.getDelegate(canvas.getNativeCanvas());
     }
 
     /**
@@ -102,7 +102,7 @@
     @LayoutlibDelegate
     /*package*/ static boolean isOpaque(Canvas thisCanvas) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return false;
         }
@@ -113,7 +113,7 @@
     @LayoutlibDelegate
     /*package*/ static int getWidth(Canvas thisCanvas) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return 0;
         }
@@ -124,7 +124,7 @@
     @LayoutlibDelegate
     /*package*/ static int getHeight(Canvas thisCanvas) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return 0;
         }
@@ -135,7 +135,7 @@
     @LayoutlibDelegate
    /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return;
         }
@@ -146,7 +146,7 @@
     @LayoutlibDelegate
     /*package*/ static void rotate(Canvas thisCanvas, float degrees) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return;
         }
@@ -157,7 +157,7 @@
     @LayoutlibDelegate
    /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return;
         }
@@ -168,7 +168,7 @@
     @LayoutlibDelegate
    /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return;
         }
@@ -204,7 +204,7 @@
     /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
             float bottom) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return false;
         }
@@ -227,7 +227,7 @@
     @LayoutlibDelegate
     /*package*/ static int save(Canvas thisCanvas, int saveFlags) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return 0;
         }
@@ -238,7 +238,7 @@
     @LayoutlibDelegate
     /*package*/ static void restore(Canvas thisCanvas) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return;
         }
@@ -249,7 +249,7 @@
     @LayoutlibDelegate
     /*package*/ static int getSaveCount(Canvas thisCanvas) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return 0;
         }
@@ -260,7 +260,7 @@
     @LayoutlibDelegate
     /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
         // get the delegate from the native int.
-        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.getNativeCanvas());
         if (canvasDelegate == null) {
             return;
         }
@@ -287,7 +287,7 @@
     /*package*/ static void drawLines(Canvas thisCanvas,
             final float[] pts, final int offset, final int count,
             Paint paint) {
-        draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
+        draw(thisCanvas.getNativeCanvas(), paint.mNativePaint, false /*compositeOnly*/,
                 false /*forceSrcMode*/, new GcSnapshot.Drawable() {
                     @Override
                     public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
diff --git a/core/res/res/drawable/stat_sys_adb.xml b/wifi/java/android/net/wifi/IWifiScanner.aidl
similarity index 61%
copy from core/res/res/drawable/stat_sys_adb.xml
copy to wifi/java/android/net/wifi/IWifiScanner.aidl
index dfc8563..fef2d117 100644
--- a/core/res/res/drawable/stat_sys_adb.xml
+++ b/wifi/java/android/net/wifi/IWifiScanner.aidl
@@ -1,13 +1,11 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
 /*
- * Copyright 2013, The Android Open Source Project
+ * Copyright (C) 2008 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ *      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,
@@ -15,9 +13,15 @@
  * 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/stat_sys_adb_am"
-        android:autoMirrored="true">
-</bitmap>
+package android.net.wifi;
+
+import android.os.Messenger;
+
+/**
+ * {@hide}
+ */
+interface IWifiScanner
+{
+    Messenger getMessenger();
+}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index d7ecaff..1cb9546 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -56,6 +56,13 @@
     public long timestamp;
 
     /**
+     * Timestamp representing date when this result was last seen, in milliseconds from 1970
+     * {@hide}
+     */
+    public long seen;
+
+
+    /**
      * The approximate distance to the AP in centimeter, if available.  Else
      * {@link UNSPECIFIED}.
      * {@hide}
@@ -114,9 +121,17 @@
             timestamp = source.timestamp;
             distanceCm = source.distanceCm;
             distanceSdCm = source.distanceSdCm;
+            seen = source.seen;
         }
     }
 
+    /** empty scan result
+     *
+     * {@hide}
+     * */
+    public ScanResult() {
+    }
+
     @Override
     public String toString() {
         StringBuffer sb = new StringBuffer();
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 6562462..85b81d9 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -21,6 +21,7 @@
 import android.os.Parcel;
 import android.text.TextUtils;
 
+import java.util.HashMap;
 import java.util.BitSet;
 
 /**
@@ -302,6 +303,156 @@
 
     /**
      * @hide
+     * dhcp server MAC address if known
+     */
+    public String dhcpServer;
+
+    /**
+     * @hide
+     * default Gateway MAC address if known
+     */
+    public String defaultGwMacAddress;
+
+    /**
+     * @hide
+     * BSSID list on which this configuration was seen.
+     * TODO: prevent this list to grow infinitely, age-out the results
+     */
+    public HashMap<String, ScanResult> scanResultCache;
+
+    /** @hide **/
+    public static int INVALID_RSSI = -127;
+
+    /**
+     * @hide
+     * A summary of the RSSI and Band status for that configuration
+     * This is used as a temporary value by the auto-join controller
+     */
+    public final class Visibility
+    {
+        public int rssi5;   // strongest 5GHz RSSI
+        public int rssi24;  // strongest 2.4GHz RSSI
+        public int num5;    // number of BSSIDs on 5GHz
+        public int num24;   // number of BSSIDs on 2.4GHz
+        public long age5;  // timestamp of the strongest 5GHz BSSID (last time it was seen)
+        public long age24;   // timestamp of the strongest 2.4GHz BSSID (last time it was seen)
+        public Visibility()
+        {
+            rssi5 = INVALID_RSSI;
+            rssi24 = INVALID_RSSI;
+        }
+        public Visibility(Visibility source)
+        {
+            rssi5 = source.rssi5;
+            rssi24 = source.rssi24;
+            age24 = source.age24;
+            age5 = source.age5;
+            num24 = source.num24;
+            num5 = source.num5;
+        }
+    }
+
+    /** @hide
+     * Cache the visibility status of this configuration.
+     * Visibility can change at any time depending on scan results availability.
+     * Owner of the WifiConfiguration is responsible to set this field based on
+     * recent scan results.
+     ***/
+    public Visibility visibility;
+
+    /** @hide
+     * calculate and set Visibility for that configuration.
+     *
+     * age in milliseconds: we will consider only ScanResults that are more recent,
+     * i.e. younger.
+     ***/
+    public Visibility setVisibility(long age) {
+        if (scanResultCache == null) {
+            visibility = null;
+            return null;
+        }
+
+        Visibility status = new Visibility();
+
+        long now_ms = System.currentTimeMillis();
+        for(ScanResult result : scanResultCache.values()) {
+            if (result.seen == 0)
+                continue;
+
+            if ((result.frequency > 4900) && (result.frequency < 5900)) {
+                //strictly speaking: [4915, 5825]
+                //number of known BSSID on 5GHz band
+                status.num5 = status.num5 + 1;
+            } else if ((result.frequency > 2400) && (result.frequency < 2500)) {
+                //strictly speaking: [2412, 2482]
+                //number of known BSSID on 2.4Ghz band
+                status.num24 = status.num24 + 1;
+            }
+
+            if ((now_ms - result.seen) > age) continue;
+
+            if ((result.frequency > 4900) && (result.frequency < 5900)) {
+                if (result.level > status.rssi5) {
+                    status.rssi5 = result.level;
+                    status.age5 = result.seen;
+                }
+            } else if ((result.frequency > 2400) && (result.frequency < 2500)) {
+                if (result.level > status.rssi24) {
+                    status.rssi24 = result.level;
+                    status.age24 = result.seen;
+                }
+            }
+        }
+        visibility = status;
+        return status;
+    }
+
+    /** @hide */
+    public static final int AUTO_JOIN_ENABLED                   = 0;
+    /** @hide */
+    public static final int AUTO_JOIN_DISABLED_ON_AUTH_FAILURE  = 1;
+    /**
+     * @hide
+     */
+    public int autoJoinStatus;
+
+    /**
+     * @hide
+     * Indicate that a WifiConfiguration is temporary and should not be saved
+     * nor considered by AutoJoin.
+     */
+    public boolean ephemeral;
+
+    /**
+     * @hide
+     * Connect choices
+     *
+     * remember the keys identifying the known WifiConfiguration over which this configuration
+     * was preferred by user or a "WiFi Network Management app", that is,
+     * a WifiManager.CONNECT_NETWORK or SELECT_NETWORK was received while this configuration
+     * was visible to the user:
+     * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
+     *
+     * The integer represents the configuration's RSSI at that time (useful?)
+     *
+     * The overall auto-join algorithm make use of past connect choice so as to sort configuration,
+     * the exact algorithm still fluctuating as of 5/7/2014
+     *
+     */
+    public HashMap<String, Integer> connectChoices;
+
+    /**
+     * @hide
+     * Linked Configurations: represent the set of Wificonfigurations that are equivalent
+     * regarding roaming and auto-joining.
+     * The linked configuration may or may not have same SSID, and may or may not have same
+     * credentials.
+     * For instance, linked configurations will have same defaultGwMacAddress or same dhcp server.
+     */
+    public HashMap<String, Integer>  linkedConfigurations;
+
+    /**
+     * @hide
      */
     public enum ProxySettings {
         /* No proxy is to be used. Any existing proxy settings
@@ -346,6 +497,7 @@
         ipAssignment = IpAssignment.UNASSIGNED;
         proxySettings = ProxySettings.UNASSIGNED;
         linkProperties = new LinkProperties();
+        autoJoinStatus = AUTO_JOIN_ENABLED;
     }
 
     /**
@@ -354,6 +506,12 @@
      * @hide
      */
     public boolean isValid() {
+        if (SSID == null)
+            return false;
+
+        if (allowedKeyManagement == null)
+            return false;
+
         if (allowedKeyManagement.cardinality() > 1) {
             if (allowedKeyManagement.cardinality() != 2) {
                 return false;
@@ -369,6 +527,32 @@
 
         // TODO: Add more checks
         return true;
+
+    }
+
+    /**
+     * most recent time we have seen this configuration
+     * @return most recent scanResult
+     * @hide
+     */
+    public ScanResult lastSeen() {
+        ScanResult mostRecent = null;
+
+        if (scanResultCache == null) {
+            return null;
+        }
+
+        for (ScanResult result : scanResultCache.values()) {
+            if (mostRecent == null) {
+                if (result.seen != 0)
+                   mostRecent = result;
+            } else {
+                if (result.seen > mostRecent.seen) {
+                   mostRecent = result;
+                }
+            }
+        }
+        return mostRecent;
     }
 
     @Override
@@ -570,7 +754,48 @@
         return KeyMgmt.NONE;
     }
 
-    /** Implement the Parcelable interface {@hide} */
+    /* @hide
+     * Cache the config key, this seems useful as a speed up since a lot of
+     * lookups in the config store are done and based on this key.
+     */
+    String mCachedConfigKey;
+
+    /** @hide
+     *  return the string used to calculate the hash in WifiConfigStore
+     *  and uniquely identify this WifiConfiguration
+     */
+    public String configKey(boolean allowCached) {
+        String key;
+        if (allowCached && mCachedConfigKey != null) {
+            key = mCachedConfigKey;
+        } else {
+            key = this.SSID;
+            if (key == null)
+                key = "";
+            if (this.wepKeys[0] != null) {
+                key = key + "-WEP";
+            }
+            if (this.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
+                key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK];
+            }
+            if (this.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
+                    this.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
+                key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+            }
+            mCachedConfigKey = key;
+        }
+        return key;
+    }
+
+    /** @hide
+     * get configKey, force calculating the config string
+     */
+    public String configKey() {
+        return configKey(false);
+    }
+
+
+        /** Implement the Parcelable interface {@hide} */
     public int describeContents() {
         return 0;
     }
@@ -603,8 +828,32 @@
 
             ipAssignment = source.ipAssignment;
             proxySettings = source.proxySettings;
+
+            defaultGwMacAddress = source.defaultGwMacAddress;
+
             linkProperties = new LinkProperties(source.linkProperties);
-        }
+            if ((source.scanResultCache != null) && (source.scanResultCache.size() > 0)) {
+                scanResultCache = new HashMap<String, ScanResult>();
+                scanResultCache.putAll(source.scanResultCache);
+            }
+
+            if ((source.connectChoices != null) && (source.connectChoices.size() > 0)) {
+                connectChoices = new HashMap<String, Integer>();
+                connectChoices.putAll(source.connectChoices);
+            }
+
+            if ((source.linkedConfigurations != null)
+                    && (source.linkedConfigurations.size() > 0)) {
+                linkedConfigurations = new HashMap<String, Integer>();
+                linkedConfigurations.putAll(source.linkedConfigurations);
+            }
+            mCachedConfigKey = null; //force null configKey
+            autoJoinStatus = source.autoJoinStatus;
+
+            if (source.visibility != null) {
+                visibility = new Visibility(source.visibility);
+            }
+       }
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -633,6 +882,10 @@
         dest.writeString(ipAssignment.name());
         dest.writeString(proxySettings.name());
         dest.writeParcelable(linkProperties, flags);
+
+        dest.writeString(dhcpServer);
+        dest.writeString(defaultGwMacAddress);
+        dest.writeInt(autoJoinStatus);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -664,6 +917,10 @@
                 config.proxySettings = ProxySettings.valueOf(in.readString());
                 config.linkProperties = in.readParcelable(null);
 
+                config.dhcpServer = in.readString();
+                config.defaultGwMacAddress = in.readString();
+                config.autoJoinStatus = in.readInt();
+
                 return config;
             }
 
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
new file mode 100644
index 0000000..e02e14c
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.SparseArray;
+
+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;
+
+
+/**
+ * This class provides a way to scan the Wifi universe around the device
+ * Get an instance of this class by calling
+ * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context
+ * .WIFI_SCANNING_SERVICE)}.
+ * @hide
+ */
+public class WifiScanner {
+
+    public static final int WIFI_BAND_UNSPECIFIED = 0;      /* not specified */
+    public static final int WIFI_BAND_24_GHZ = 1;           /* 2.4 GHz band */
+    public static final int WIFI_BAND_5_GHZ = 2;            /* 5 GHz band without DFS channels */
+    public static final int WIFI_BAND_5_GHZ_DFS_ONLY  = 4;  /* 5 GHz band with DFS channels */
+    public static final int WIFI_BAND_5_GHZ_WITH_DFS  = 6;  /* 5 GHz band with DFS channels */
+    public static final int WIFI_BAND_BOTH = 3;             /* both bands without 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 */
+    public static final int MAX_SCAN_PERIOD_MS = 1024000;   /* maximum supported period */
+
+    public static final int REASON_SUCCEEDED = 0;
+    public static final int REASON_UNSPECIFIED = -1;
+    public static final int REASON_INVALID_LISTENER = -2;
+    public static final int REASON_INVALID_REQUEST = -3;
+    public static final int REASON_CONFLICTING_REQUEST = -4;
+
+    public static interface ActionListener {
+        public void onSuccess(Object result);
+        public void onFailure(int reason, Object exception);
+    }
+
+    /**
+     * gives you all the possible channels; channel is specified as an
+     * integer with frequency in MHz i.e. channel 1 is 2412
+     */
+    public List<Integer> getAvailableChannels(int band) {
+        return null;
+    }
+
+    /**
+     * provides channel specification to the APIs
+     */
+    public static class ChannelSpec {
+        public int frequency;
+        public boolean passive;                                    /* ignored on DFS channels */
+        public int dwellTimeMS;                                    /* not supported for now */
+
+        public ChannelSpec(int frequency) {
+            this.frequency = frequency;
+            passive = false;
+            dwellTimeMS = 0;
+        }
+    }
+
+    public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0;
+    public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1;
+    public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2;
+
+    /**
+     * scan configuration parameters
+     */
+    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 */
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(band);
+            dest.writeInt(periodInMs);
+            dest.writeInt(channels.length);
+
+            for (int i = 0; i < channels.length; i++) {
+                dest.writeInt(channels[i].frequency);
+                dest.writeInt(channels[i].dwellTimeMS);
+                dest.writeInt(channels[i].passive ? 1 : 0);
+            }
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<ScanSettings> CREATOR =
+                new Creator<ScanSettings>() {
+                    public ScanSettings createFromParcel(Parcel in) {
+
+                        ScanSettings settings = new ScanSettings();
+                        settings.band = in.readInt();
+                        settings.periodInMs = in.readInt();
+                        int num_channels = in.readInt();
+                        settings.channels = new ChannelSpec[num_channels];
+                        for (int i = 0; i < num_channels; i++) {
+                            int frequency = in.readInt();
+
+                            ChannelSpec spec = new ChannelSpec(frequency);
+                            spec.dwellTimeMS = in.readInt();
+                            spec.passive = in.readInt() == 1;
+                            settings.channels[i] = spec;
+                        }
+
+                        return settings;
+                    }
+
+                    public ScanSettings[] newArray(int size) {
+                        return new ScanSettings[size];
+                    }
+                };
+
+    }
+
+    public static class InformationElement {
+        public int id;
+        public byte[] bytes;
+    }
+
+    public static class FullScanResult {
+        public ScanResult result;
+        public InformationElement informationElements[];
+    }
+
+    /** @hide */
+    public static class ParcelableScanResults implements Parcelable {
+        public ScanResult mResults[];
+
+        public ParcelableScanResults(ScanResult[] results) {
+            mResults = results;
+        }
+
+        public ScanResult[] getResults() {
+            return mResults;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mResults.length);
+            for (int i = 0; i < mResults.length; i++) {
+                ScanResult result = mResults[i];
+                result.writeToParcel(dest, flags);
+            }
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<ParcelableScanResults> CREATOR =
+                new Creator<ParcelableScanResults>() {
+                    public ParcelableScanResults createFromParcel(Parcel in) {
+                        int n = in.readInt();
+                        ScanResult results[] = new ScanResult[n];
+                        for (int i = 0; i < n; i++) {
+                            results[i] = ScanResult.CREATOR.createFromParcel(in);
+                        }
+                        return new ParcelableScanResults(results);
+                    }
+
+                    public ParcelableScanResults[] newArray(int size) {
+                        return new ParcelableScanResults[size];
+                    }
+                };
+    }
+
+    /**
+     * 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.
+     */
+    public interface ScanListener extends ActionListener {
+        public void onPeriodChanged(int periodInMs);
+        public void onResults(ScanResult[] results);
+        public void onFullResult(FullScanResult fullScanResult);
+    }
+
+    public void scan(ScanSettings settings, ScanListener listener) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_SCAN, 0, putListener(listener), settings);
+    }
+    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) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, removeListener(listener));
+    }
+    public void retrieveScanResults(boolean flush, ScanListener listener) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_GET_SCAN_RESULTS, 0, getListenerKey(listener));
+    }
+
+    public static class HotspotInfo {
+        public String bssid;
+        public int low;                                            /* minimum RSSI */
+        public int high;                                           /* maximum RSSI */
+    }
+
+    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 */
+        public HotspotInfo[] hotspotInfos;
+    }
+
+    /* overrides the significant wifi change state machine configuration */
+    public void configureSignificantWifiChange(
+            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 */
+            HotspotInfo[] hotspotInfos                      /* signal thresholds to crosss */
+            )
+    {
+        validateChannel();
+        WifiChangeSettings settings = new WifiChangeSettings();
+        settings.rssiSampleSize = rssiSampleSize;
+        settings.lostApSampleSize = lostApSampleSize;
+        settings.unchangedSampleSize = unchangedSampleSize;
+        settings.minApsBreachingThreshold = minApsBreachingThreshold;
+        settings.hotspotInfos = hotspotInfos;
+
+        sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+    }
+
+    public interface SignificantWifiChangeListener extends ActionListener {
+        public void onChanging(ScanResult[] results);           /* changes are found */
+        public void onQuiescence(ScanResult[] results);         /* changes settled down */
+    }
+
+    public void trackSignificantWifiChange(SignificantWifiChangeListener listener) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, putListener(listener));
+    }
+    public void untrackSignificantWifiChange(SignificantWifiChangeListener listener) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, removeListener(listener));
+    }
+
+    public void configureSignificantWifiChange(WifiChangeSettings settings) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+    }
+
+    public static interface HotlistListener extends ActionListener {
+        public void onFound(ScanResult[] results);
+    }
+
+    /** @hide */
+    public static class HotlistSettings implements Parcelable {
+        public HotspotInfo[] hotspotInfos;
+        public int apLostThreshold;
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(apLostThreshold);
+            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);
+            }
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<HotlistSettings> CREATOR =
+                new Creator<HotlistSettings>() {
+                    public HotlistSettings createFromParcel(Parcel in) {
+                        HotlistSettings settings = new HotlistSettings();
+                        settings.apLostThreshold = in.readInt();
+                        int n = in.readInt();
+                        settings.hotspotInfos = new HotspotInfo[n];
+                        for (int i = 0; i < n; i++) {
+                            HotspotInfo info = new HotspotInfo();
+                            info.bssid = in.readString();
+                            info.low = in.readInt();
+                            info.high = in.readInt();
+                            settings.hotspotInfos[i] = info;
+                        }
+                        return settings;
+                    }
+
+                    public HotlistSettings[] newArray(int size) {
+                        return new HotlistSettings[size];
+                    }
+                };
+    }
+
+    public void setHotlist(HotspotInfo[] hotspots,
+            int apLostThreshold, HotlistListener listener) {
+        validateChannel();
+        HotlistSettings settings = new HotlistSettings();
+        settings.hotspotInfos = hotspots;
+        sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, putListener(listener), settings);
+    }
+
+    public void resetHotlist(HotlistListener listener) {
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, removeListener(listener));
+    }
+
+
+    /* private members and methods */
+
+    private static final String TAG = "WifiScanner";
+    private static final boolean DBG = true;
+
+    /* commands for Wifi Service */
+    private static final int BASE = Protocol.BASE_WIFI_SCANNER;
+
+    /** @hide */
+    public static final int CMD_SCAN                        = BASE + 0;
+    /** @hide */
+    public static final int CMD_START_BACKGROUND_SCAN       = BASE + 2;
+    /** @hide */
+    public static final int CMD_STOP_BACKGROUND_SCAN        = BASE + 3;
+    /** @hide */
+    public static final int CMD_GET_SCAN_RESULTS            = BASE + 4;
+    /** @hide */
+    public static final int CMD_SCAN_RESULT                 = BASE + 5;
+    /** @hide */
+    public static final int CMD_SET_HOTLIST                 = BASE + 6;
+    /** @hide */
+    public static final int CMD_RESET_HOTLIST               = BASE + 7;
+    /** @hide */
+    public static final int CMD_AP_FOUND                    = BASE + 9;
+    /** @hide */
+    public static final int CMD_AP_LOST                     = BASE + 10;
+    /** @hide */
+    public static final int CMD_START_TRACKING_CHANGE       = BASE + 11;
+    /** @hide */
+    public static final int CMD_STOP_TRACKING_CHANGE        = BASE + 12;
+    /** @hide */
+    public static final int CMD_CONFIGURE_WIFI_CHANGE       = BASE + 13;
+    /** @hide */
+    public static final int CMD_WIFI_CHANGE_DETECTED        = BASE + 15;
+    /** @hide */
+    public static final int CMD_WIFI_CHANGES_STABILIZED     = BASE + 16;
+    /** @hide */
+    public static final int CMD_OP_SUCCEEDED                = BASE + 17;
+    /** @hide */
+    public static final int CMD_OP_FAILED                   = BASE + 18;
+    /** @hide */
+    public static final int CMD_PERIOD_CHANGED              = BASE + 19;
+    /** @hide */
+    public static final int CMD_FULL_SCAN_RESULT            = BASE + 20;
+
+    private Context mContext;
+    private IWifiScanner mService;
+
+    private static final int INVALID_KEY = 0;
+    private static int sListenerKey = 1;
+
+    private static final SparseArray sListenerMap = new SparseArray();
+    private static final Object sListenerMapLock = new Object();
+
+    private static AsyncChannel sAsyncChannel;
+    private static CountDownLatch sConnected;
+
+    private static final Object sThreadRefLock = new Object();
+    private static int sThreadRefCount;
+    private static HandlerThread sHandlerThread;
+
+    /**
+     * Create a new WifiScanner instance.
+     * Applications will almost always want to use
+     * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
+     * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
+     * @param context the application context
+     * @param service the Binder interface
+     * @hide
+     */
+    public WifiScanner(Context context, IWifiScanner service) {
+        mContext = context;
+        mService = service;
+        init();
+    }
+
+    private void init() {
+        synchronized (sThreadRefLock) {
+            if (++sThreadRefCount == 1) {
+                Messenger messenger = null;
+                try {
+                    messenger = mService.getMessenger();
+                } catch (RemoteException e) {
+                    /* do nothing */
+                } catch (SecurityException e) {
+                    /* do nothing */
+                }
+
+                if (messenger == null) {
+                    sAsyncChannel = null;
+                    return;
+                }
+
+                sHandlerThread = new HandlerThread("WifiScanner");
+                sAsyncChannel = new AsyncChannel();
+                sConnected = new CountDownLatch(1);
+
+                sHandlerThread.start();
+                Handler handler = new ServiceHandler(sHandlerThread.getLooper());
+                sAsyncChannel.connect(mContext, handler, messenger);
+                try {
+                    sConnected.await();
+                } catch (InterruptedException e) {
+                    Log.e(TAG, "interrupted wait at init");
+                }
+            }
+        }
+    }
+
+    private void validateChannel() {
+        if (sAsyncChannel == null) throw new IllegalStateException(
+                "No permission to access and change wifi or a bad initialization");
+    }
+
+    private static int putListener(Object listener) {
+        if (listener == null) return INVALID_KEY;
+        int key;
+        synchronized (sListenerMapLock) {
+            do {
+                key = sListenerKey++;
+            } while (key == INVALID_KEY);
+            sListenerMap.put(key, listener);
+        }
+        return key;
+    }
+
+    private static Object getListener(int key) {
+        if (key == INVALID_KEY) return null;
+        synchronized (sListenerMapLock) {
+            Object listener = sListenerMap.get(key);
+            return listener;
+        }
+    }
+
+    private static int getListenerKey(Object listener) {
+        if (listener == null) return INVALID_KEY;
+        synchronized (sListenerMapLock) {
+            int index = sListenerMap.indexOfValue(listener);
+            if (index == -1) {
+                return INVALID_KEY;
+            } else {
+                return sListenerMap.keyAt(index);
+            }
+        }
+    }
+
+    private static Object removeListener(int key) {
+        if (key == INVALID_KEY) return null;
+        synchronized (sListenerMapLock) {
+            Object listener = sListenerMap.get(key);
+            sListenerMap.remove(key);
+            return listener;
+        }
+    }
+
+    private static int removeListener(Object listener) {
+        int key = getListenerKey(listener);
+        if (key == INVALID_KEY) return key;
+        synchronized (sListenerMapLock) {
+            sListenerMap.remove(key);
+            return key;
+        }
+    }
+
+    private static class ServiceHandler extends Handler {
+        ServiceHandler(Looper looper) {
+            super(looper);
+        }
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
+                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+                        sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+                    } else {
+                        Log.e(TAG, "Failed to set up channel connection");
+                        // This will cause all further async API calls on the WifiManager
+                        // to fail and throw an exception
+                        sAsyncChannel = null;
+                    }
+                    sConnected.countDown();
+                    return;
+                case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
+                    return;
+                case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+                    Log.e(TAG, "Channel connection lost");
+                    // This will cause all further async API calls on the WifiManager
+                    // to fail and throw an exception
+                    sAsyncChannel = null;
+                    getLooper().quit();
+                    return;
+            }
+
+            Object listener = getListener(msg.arg2);
+            if (DBG) Log.d(TAG, "listener key = " + msg.arg2);
+
+            switch (msg.what) {
+                    /* ActionListeners grouped together */
+                case CMD_OP_SUCCEEDED :
+                    ((ActionListener) listener).onSuccess(msg.obj);
+                    break;
+                case CMD_OP_FAILED :
+                    ((ActionListener) listener).onFailure(msg.arg1, msg.obj);
+                    break;
+                case CMD_SCAN_RESULT :
+                    ((ScanListener) listener).onResults(
+                            ((ParcelableScanResults) msg.obj).getResults());
+                    return;
+                case CMD_FULL_SCAN_RESULT :
+                    FullScanResult result = (FullScanResult) msg.obj;
+                    ((ScanListener) listener).onFullResult(result);
+                    return;
+                case CMD_AP_FOUND:
+                    ((HotlistListener) listener).onFound(
+                            ((ParcelableScanResults) msg.obj).getResults());
+                    return;
+                case CMD_WIFI_CHANGE_DETECTED:
+                    ((SignificantWifiChangeListener) listener).onChanging(
+                            ((ParcelableScanResults) msg.obj).getResults());
+                   return;
+                case CMD_WIFI_CHANGES_STABILIZED:
+                    ((SignificantWifiChangeListener) listener).onQuiescence(
+                            ((ParcelableScanResults) msg.obj).getResults());
+                    return;
+                default:
+                    if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
+                    return;
+            }
+        }
+    }
+}